user_id 的单个结果按多个日期排序

Single result for user_id sorted by multiple dates

我有一个 table 包含 positions 这个table如下:

user_id | current | started_at  | finished_at
2       |  false  | 10-07-2016  | 02-08-2016
1       |  false  | 19-07-2016  | 27-07-2016
1       |  true   | 29-07-2016  | null
3       |  true   | 20-07-2016  | null
3       |  false  | 01-07-2016  | 18-07-2016

我正在根据 current 是真还是假

使用 started_atfinished_at 日期对这个 table 进行排序]
SELECT *
FROM positions
ORDER BY
  CASE
      WHEN current = true 
          THEN started_at
      ELSE finished_at
  END
 DESC

这按预期工作正常,但现在我只想提取每个 user_id

的第一行

所以在我的示例数据中,我只想返回以下内容。

user_id | current | started_at  | finished_at
2       |  false  | 10-07-2016  | 02-08-2016
1       |  true   | 29-07-2016  | null
3       |  true   | 20-07-2016  | null

我想这可以用 GROUP BY 来完成,但我无法让它正常工作,或者我不确定是否需要子查询。

我猜你在你的例子中犯了一个错误,因为你想要的结果显示 seconduser_id 1.

您可以使用非标准 PostgreSQL DISTINCT ON 功能轻松实现您想要的:

SELECT DISTINCT ON (user_id) * FROM
   (SELECT * FROM positions
    ORDER BY
       CASE
          WHEN current = true
          THEN started_at
          ELSE finished_at
       END
    DESC) q;

这将删除每个 user_id 的第一行以外的所有内容。

这是使用 window 功能的绝佳机会。您可以使用 window 函数创建如下所示的查询:

SELECT  user_id, current, started_at, finished_at, 
  row_number() OVER (PARTITION BY user_id) AS row_number
    FROM positions
    ORDER BY CASE WHEN current = true 
       THEN started_at ELSE finished_at END DESC

这将为您提供原始 table 以及来自 window 函数的新列 "row_number"。您按 user_id 分区,因为您想按用户获取 row_number。使用您提供的 ORDER 子句。要获得完整答案,只需将此语句用作子查询,使用 WHERE 子句仅选择 row_number = 1,然后拉取所有需要的字段。 Window函数不能用在WHERE子句中,这就是你需要子查询的原因。

SELECT  user_id, current, started_at, finished_at
FROM
(
SELECT  user_id, current, started_at, finished_at, 
  row_number() OVER (PARTITION BY user_id) AS row_number
FROM positions
ORDER BY CASE WHEN current = true 
   THEN started_at ELSE finished_at END DESC
) pos
WHERE row_number= 1