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_at
或 finished_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
来完成,但我无法让它正常工作,或者我不确定是否需要子查询。
我猜你在你的例子中犯了一个错误,因为你想要的结果显示 second 行 user_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
我有一个 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_at
或 finished_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
来完成,但我无法让它正常工作,或者我不确定是否需要子查询。
我猜你在你的例子中犯了一个错误,因为你想要的结果显示 second 行 user_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