选择按某些列排序的行和不同的列

sl_*_*bug 21 postgresql greatest-n-per-group distinct-on

与 - PostgreSQL DISTINCT ON有关,使用不同的ORDER BY

我有桌子购买(product_id,purchase_at,address_id)

样本数据:

| id | product_id |   purchased_at    | address_id |
| 1  |     2      | 20 Mar 2012 21:01 |     1      |
| 2  |     2      | 20 Mar 2012 21:33 |     1      |
| 3  |     2      | 20 Mar 2012 21:39 |     2      |
| 4  |     2      | 20 Mar 2012 21:48 |     2      |
Run Code Online (Sandbox Code Playgroud)

我期望的结果是每个address_id的最近购买的产品(完整行),并且结果必须由downloaded_at字段以后代顺序排序:

| id | product_id |   purchased_at    | address_id |
| 4  |     2      | 20 Mar 2012 21:48 |     2      |
| 2  |     2      | 20 Mar 2012 21:33 |     1      |
Run Code Online (Sandbox Code Playgroud)

使用查询:

SELECT DISTINCT ON (address_id) purchases.address_id, purchases.*
FROM "purchases"
WHERE "purchases"."product_id" = 2
ORDER BY purchases.address_id ASC, purchases.purchased_at DESC
Run Code Online (Sandbox Code Playgroud)

我越来越:

| id | product_id |   purchased_at    | address_id |
| 2  |     2      | 20 Mar 2012 21:33 |     1      |
| 4  |     2      | 20 Mar 2012 21:48 |     2      |
Run Code Online (Sandbox Code Playgroud)

因此行是相同的,但顺序是错误的.有什么办法解决吗?

Mos*_*cho 17

相当明确的问题:)

SELECT t1.* FROM purchases t1
LEFT JOIN purchases t2
ON t1.address_id = t2.address_id AND t1.purchased_at < t2.purchased_at
WHERE t2.purchased_at IS NULL
ORDER BY t1.purchased_at DESC
Run Code Online (Sandbox Code Playgroud)

而且很可能是一种更快的方法:

SELECT t1.* FROM purchases t1
JOIN (
    SELECT address_id, max(purchased_at) max_purchased_at
    FROM purchases
    GROUP BY address_id
) t2
ON t1.address_id = t2.address_id AND t1.purchased_at = t2.max_purchased_at
ORDER BY t1.purchased_at DESC
Run Code Online (Sandbox Code Playgroud)

  • 这不应该是公认的答案。不支持重复购买。 (2认同)
  • 不,他正在寻找根据问题返回的单个记录。如果购买的_at与另一条记录相同,那么这个解决方案实际上并没有解决它,并且像我这样来这里寻找同一问题解决方案的任何其他人通常会将接受的答案视为“理想”方法,但在这种情况下它是完全错误的。 (2认同)
  • @bernacle.m 问题中没有任何地方指出答案应该返回“单个记录”或OP是“他”。您应该仔细阅读问题,而不是跳到所选答案并假设您的问题与OP 的问题匹配。更不用说 *purchased_at* 可能是唯一密钥的一部分,但您也不知道。 (2认同)

dbe*_*hur 8

您的ORDER BY由DISTINCT ON用于选择要生成的每个不同address_id的哪一行.如果您想要对结果记录进行排序,请将DISTINCT设置为子选择并对其结果进行排序:

SELECT * FROM
(
  SELECT DISTINCT ON (address_id) purchases.address_id, purchases.*
  FROM "purchases"
  WHERE "purchases"."product_id" = 2
  ORDER BY purchases.address_id ASC, purchases.purchased_at DESC
) distinct_addrs
order by distinct_addrs.purchased_at DESC
Run Code Online (Sandbox Code Playgroud)

  • 这实际上是唯一有效的答案。您也可以在第二个选择行中使用“SELECT DISTINCT ON (address_id) *” (2认同)