SQL select 按 has_many 关系的最新元素的列
SQL select by column of newest element of has_many relationship
在我的项目中我有一个tasks
(id, name) table。我还有一个 status_updates
(id, task_id, user_id, status, created_at) table.
我想要 select 最新 status_update 等于特定状态的任务。
但是,我不知道如何组合以下内容:
- 每个任务只使用最新的status_update。
- 过滤掉状态不正确的 status_update。
- 将其包装在 INNER JOIN 中,因此最终结果是一组任务。
使用GROUP_BY时,好像1.和2.互相抵消了。一个例子:
SELECT * FROM status_updates GROUP BY task_id ORDER created_at DESC
仅返回每个任务的最新 status_update。
然而,这:
SELECT * FROM status_updates WHERE status='1' GROUP BY task_id ORDER created_at DESC
在 ORDER 之前执行 WHERE,从而返回 状态正确的最新的,而不是 来自最新的状态,只有状态正确的那些正确的状态.
我也尝试过使用 HAVING,但因为它只适用于聚合列,所以我不知道如何正确使用它,或者它在这种情况下是否有帮助。
我在 Rails 上使用 Ruby,所以我想要一个既适用于 MySQL 又适用于 SQLite 的答案。
使用子查询:
SELECT
T.id,
T.name,
SU.status
FROM
Tasks T
INNER JOIN (SELECT task_id, MAX(created_at) AS max_created_at FROM Status_Updates GROUP BY task_id) SQ ON SQ.task_id = T.id
INNER JOIN Status_Updates SU ON
SU.task_id = SQ.task_id AND
SU.created_at = SQ.max_created_at
WHERE
SU.status = '1'
使用 window 函数和 CTE(虽然您的 RDBMS 目前不支持,但很多人支持,将来可能支持)。这个的优点是它可以更好地处理联系:
WITH MyCTE AS
(
SELECT
T.id,
T.name,
SU.status,
ROW_NUMBER OVER(PARTITION BY T.id ORDER BY SU.created_at DESC, id DESC) AS row_num
FROM
Tasks T
INNER JOIN Status_Updates SU ON SU.task_id = T.id
)
SELECT
id,
name,
status
FROM
MyCTE
WHERE
row_num = 1
在我的项目中我有一个tasks
(id, name) table。我还有一个 status_updates
(id, task_id, user_id, status, created_at) table.
我想要 select 最新 status_update 等于特定状态的任务。
但是,我不知道如何组合以下内容:
- 每个任务只使用最新的status_update。
- 过滤掉状态不正确的 status_update。
- 将其包装在 INNER JOIN 中,因此最终结果是一组任务。
使用GROUP_BY时,好像1.和2.互相抵消了。一个例子:
SELECT * FROM status_updates GROUP BY task_id ORDER created_at DESC
仅返回每个任务的最新 status_update。 然而,这:
SELECT * FROM status_updates WHERE status='1' GROUP BY task_id ORDER created_at DESC
在 ORDER 之前执行 WHERE,从而返回 状态正确的最新的,而不是 来自最新的状态,只有状态正确的那些正确的状态.
我也尝试过使用 HAVING,但因为它只适用于聚合列,所以我不知道如何正确使用它,或者它在这种情况下是否有帮助。
我在 Rails 上使用 Ruby,所以我想要一个既适用于 MySQL 又适用于 SQLite 的答案。
使用子查询:
SELECT
T.id,
T.name,
SU.status
FROM
Tasks T
INNER JOIN (SELECT task_id, MAX(created_at) AS max_created_at FROM Status_Updates GROUP BY task_id) SQ ON SQ.task_id = T.id
INNER JOIN Status_Updates SU ON
SU.task_id = SQ.task_id AND
SU.created_at = SQ.max_created_at
WHERE
SU.status = '1'
使用 window 函数和 CTE(虽然您的 RDBMS 目前不支持,但很多人支持,将来可能支持)。这个的优点是它可以更好地处理联系:
WITH MyCTE AS
(
SELECT
T.id,
T.name,
SU.status,
ROW_NUMBER OVER(PARTITION BY T.id ORDER BY SU.created_at DESC, id DESC) AS row_num
FROM
Tasks T
INNER JOIN Status_Updates SU ON SU.task_id = T.id
)
SELECT
id,
name,
status
FROM
MyCTE
WHERE
row_num = 1