在一列上选择 Distinct,不按该列排序

rob*_*y22 4 sql postgresql sql-order-by distinct-on

我试图只选择我正在查询的表的 ID,并且仍然能够指定其他列的排序。

首先我试着简单地做:

SELECT DISTINCT countries.id
FROM countries
...
ORDER BY province_infos.population DESC, country_infos.population ASC
Run Code Online (Sandbox Code Playgroud)

这行不通,因为 for SELECT DISTINCTORDER BY表达式必须出现在选择列表中,并返回错误。

如果我添加province_infos.populationand country_infos.population,它可以工作,但是我会得到重复的 ID,这是我不能拥有的。

为了解决这个问题,我尝试使用DISTINCT ON()

SELECT DISTINCT ON (countries.id)
    countries.id, country_infos.population, province_infos.population
FROM countries
...
ORDER BY province_infos.population DESC, country_infos.population ASC
Run Code Online (Sandbox Code Playgroud)

然后给了我错误SELECT DISTINCT ON expressions must match initial ORDER BY expressions。我也不能不SELECT DISTINCT ON订购专栏。

似乎唯一可行的方法是执行以下操作:

SELECT DISTINCT ON (countries.id) 
    countries.id
FROM countries
...
ORDER BY countries.id DESC, province_infos.population DESC, country_infos.population ASC
Run Code Online (Sandbox Code Playgroud)

不幸的是,我不能这样做,因为我不能按 ID 订购,因为它会影响其他订单的结果。似乎不按 ID 排序的唯一方法是,如果我DISTINCT从选择中删除,但是我会得到重复项。

有谁知道我该如何解决这个问题?

编辑:...我省略不应该是相关的,但如果你希望看到的:

JOIN country_infos ON country_infos.country_refer = countries.id
JOIN languages ON languages.country_refer = countries.id
JOIN provinces ON provinces.country_refer = countries.id
JOIN province_infos ON province_infos.province_refer = provinces.id
WHERE country_infos.population > 10.3
AND languages.alphabet = 'Latin'
Run Code Online (Sandbox Code Playgroud)

而且我不只是想让它为这个特定的查询工作。这只是我用来解释困境的一个例子。我正在根据任意数据结构自动生成这些类型的查询。

Geo*_*e S 7

您的问题的一般答案是,在 postgresql 的 SELECT 语句中使用 DISTINCT ON (x, ...) 时,数据库会按 distinct 子句中的值进行排序,以便轻松判断行是否具有不同的值(一旦它们按值排序,db 只需通过一次即可删除重复项,并且只需要比较相邻的行。因此,db 会强制您按不同子句中的相同列进行排序。

您可以通过将原始查询设为子查询来解决此问题,如下所示:

SELECT t.id FROM
  (SELECT DISTINCT ON (countries.id) countries.id
    , province_infos.population
    , country_infos.founding_date
   FROM countries
   ...
   ORDER BY countries.id, province_infos.population DESC, country_infos.founding_date  ASC 
  )t
ORDER BY t.population DESC, T.founding_date ASC
Run Code Online (Sandbox Code Playgroud)