TSQL 左连接,只有右起最后一行

Posted

技术标签:

【中文标题】TSQL 左连接,只有右起最后一行【英文标题】:TSQL left join and only last row from right 【发布时间】:2011-01-17 21:38:38 【问题描述】:

我正在编写 sql 查询来获取帖子,并且只有该帖子的最后一条评论(如果存在)。 但我无法找到一种方法来限制左连接中右列仅 1 行。

这是此查询的示例。

SELECT post.id, post.title,comment.id,comment.message
from post
left outer join comment
on post.id=comment.post_id

如果帖子有 3 个 cmets,我会得到 3 行这个帖子,但我只想要 1 行最后评论(按日期排序)。

有人可以帮我解决这个问题吗?

【问题讨论】:

【参考方案1】:
SELECT  post.id, post.title, comment.id, comment.message
FROM    post
OUTER APPLY
        (
        SELECT  TOP 1 *
        FROM    comment с
        WHERE   c.post_id = post.id
        ORDER BY
                date DESC
        ) comment

SELECT  *
FROM    (
        SELECT  post.id, post.title, comment.id, comment.message,
                ROW_NUMBER() OVER (PARTITION BY post.id ORDER BY comment.date DESC) AS rn
        FROM    post
        LEFT JOIN
                comment
        ON      comment.post_id = post.id
        ) q
WHERE   rn = 1

前者对于每个帖子中有很多 cmets 的帖子效率更高;后者对于许多帖子中只有很少的 cmets 更有效。

【讨论】:

感谢您的回答。我使用下一个代码。 SELECT post.id, post.title,c.id as comment_id,c.message from post left outer join (select comment.id,comment.post_id,comment.message, ROW_NUMBER() OVER (PARTITION BY comment.post_id ORDER BY comment .date DESC) AS rn from comment) c on post.id=c.post_id where c.rn=1 or c.rn is null APPLY 运算符为我解决了这个问题。我正在进行一对多连接,但需要将右侧匹配减少到仅最近创建的匹配。谢谢! 将这两个放在一起显示估计的查询计划很有趣,apply 选项是查询成本的 99% :o @FelipeSabino:如果您在大象笼子上看到“水牛”标志,请不要相信自己的眼睛。【参考方案2】:

子查询:

SELECT p.id, p.title, c.id, c.message
FROM post p
LEFT join comment c
ON c.post_id = p.id AND c.id = 
                 (SELECT MAX(c.id) FROM comment c2 WHERE c2.post_id = p.id)

【讨论】:

如果我没有遗漏什么,这应该比我的执行计划所接受的答案快得多(比如 10 倍)。 对我来说,这似乎比在接受的答案中使用庞大的子查询更有效。 ***.com/questions/4692419/… 中有相关的答案。它在子查询中使用 TOP 1/ORDER BY 解决方案而不是 MAX。 我相信这是更简短更好的答案。 这将在按 ID 排序时返回最后一条评论,而不是按 OP 要求的日期排序【参考方案3】:

您需要加入一个返回帖子最后评论的子查询。例如:

select post.id, post.title. lastpostid, lastcommentmessage
from post
inner join
(
    select post.id as lastpostid, max(comment.id) as lastcommentmessage
    from post
    inner join comment on commment.post_id = post.id
    group by post.id
) lastcomment
    on lastpostid = post.id

【讨论】:

【参考方案4】:

几个选项....

一种方法是在以下位置进行 JOIN:

SELECT TOP 1 comment.message FROM comment ORDER BY comment.id DESC

(注意我假设 comment.id 是一个身份字段)

【讨论】:

如果Identity字段有负增量怎么办? 你遇到过这样的事情吗?【参考方案5】:

什么版本的 SQL Server?如果您有可用的 Row_Number() 函数,您可以按照“first”对您的任何含义对 cme​​ts 进行排序,然后添加“where RN=1”子句。在我的脑海中没有一个方便的示例或正确的语法,但确实有大量的查询可以做到这一点。其他帖子都是你可以做到这一点的 1000 种方式。

我会说它,看看哪一个最适合你。

【讨论】:

【参考方案6】:

你没有说你的日期字段的具体名称,所以我填写了[DateCreated]。这与上面 AGoodDisplayName 的帖子基本相同,但使用日期字段而不是依赖 ID 列排序。

SELECT post.id, post.title, comment.id, comment.message
FROM post p
LEFT OUTER JOIN comment
ON comment.id = (
    SELECT TOP 1 id
    FROM comment
    WHERE p.id = post_id
    ORDER BY [DateCreated] ASC
)

【讨论】:

以上是关于TSQL 左连接,只有右起最后一行的主要内容,如果未能解决你的问题,请参考以下文章

MySQL左连接多对一行

SQL将多行左连接成一行

MySQL 三表链式左连接,按最后一个表过滤

在两个表mysql上左连接时获取最后修改日期

缓慢的 MySQL 查询:有没有办法避免对左连接的每一行进行条件选择计数?

flex 布局换行后最后一行左对齐