【问题标题】:Getting a certain number of results from a related table in SQL Server从 SQL Server 中的相关表中获取一定数量的结果
【发布时间】:2012-03-22 09:28:55
【问题描述】:

我有一个帖子和一个 cmets 表:

Post (id, title)
Comment(id, postid, comment, commentdate)

我正在尝试选择带有评论日期的最新 10 个帖子。得到这个的查询是什么?

例子:

如果我想获取最新的 3 个帖子:

Post
---
1 P1
2 P2
3 P3
4 P4

Comment
---
1 1 C1 01:01
2 3 C2 01:02
3 3 C3 01:03
4 2 C4 01:04
5 2 C5 01:05
6 1 C6 01:06
7 4 C7 01:07
8 4 C8 01:08

Exptected result:
---

4 P4 01:08
1 P1 01:06
2 P2 01:05

从最后一条记录中搜索评论表,在 postid 列中,我分别找到了 4、1 和 2(并且很明显)。我找到了 3 个 cmets,然后就停在那里。

【问题讨论】:

  • 为什么post 3不在预期结果中?另外,您能告诉我们您使用的是什么版本的 SQL Server 吗? related 标记非常无用,但 sql-server-2005 将是,例如。
  • 帖子 3 不在结果中,因为最新评论的 3 个帖子是 P4、P1(在 P4 之前评论)和 P2(在 P1 之前评论)。
  • 那你能澄清一下你想要前3还是前10?您的问题在不同的地方都要求。

标签: sql sql-server sql-server-2008 tsql join


【解决方案1】:

我认为最简单的万无一失的方法是这样的:

SELECT TOP 10
       id,
       title,
       (SELECT MAX(commentdate)
          FROM comment
         WHERE postid = post.id
       ) AS commentdate
  FROM post
 ORDER BY commentdate DESC
;

但我不希望它表现得很好。 (它会为每个帖子找到最近的评论,然后使用它来查找最近的 cmets 是最新的十个帖子。)

一种性能会更好,但在某些情况下可能包含少于十个结果的风险的方法是这样的:

SELECT TOP 10
       id,
       title,
       (SELECT MAX(commentdate)
          FROM comment
         WHERE postid = post.id
       ) AS commentdate
  FROM post
 WHERE id IN
        ( SELECT TOP 100
                 postid
            FROM comment
           ORDER BY commentdate DESC
        )
 ORDER BY commentdate DESC
;

找到最近 100 个 cmets 所属的帖子(最多 100 个帖子),然后将上述方法应用于这些帖子。 (它可能返回少于 10 个帖子的原因是,最近的 100 个 cmets 可能都只属于 9 个帖子——或者只有 5 个帖子,或者只有 1 个帖子。)

(免责声明:我没有测试过上述任何一个查询。)

【讨论】:

  • 语法不正确(两个查询都缺少 FROM),我认为您的意思是前 3 名,而不是前 10 名。
  • @AaronBertrand:我已经添加了缺少的FROM post,谢谢。不,我的意思是前 10 名:这就是 OP 指定的内容:“我正在尝试选择带有评论日期的最新 10 篇评论。”您可能对以下示例感到困惑:“如果我试图获取最新的 3 个帖子:[...]”(强调我的)。
  • 我同意这个问题有些混乱,但是如果他想要前 3 名,那么发布 3 会不会在预期的结果中?我已经要求对此进行确认,但他不想显示第 3 个帖子,因为它不在前 3 个中。另请参阅“我找到 3 个 cmets 并停在那里。”
  • @AaronBertrand:我认为这个问题没有任何混淆。该问题解释说,实际所需的查询是获取 10 个最近的帖子;但是示例结果只有 三个,因为这样更容易显示。就像我问的是如何打印前 1,000 个素数的程序一样,我可能会显示仅包含前 10 个素数的示例输出,并带有与 OP 完全相同的解释性说明。 (“我找到 3 个 cmets 然后我就停在那里”是该示例的一部分,所以自然是前 3 名而不是前 10 名。)
【解决方案2】:

试试:

SELECT      TOP 3 Post.postId
            , Post.post
            , latestComment.leftAt
FROM        Post
            INNER JOIN (
                SELECT      postId
                            , MAX(leftAt) AS leftAt
                FROM        Comment
                GROUP BY    postId
            ) AS latestComment
              ON    Post.postId = latestComment.postId
ORDER BY    latestComment.leftAt DESC
            , Post.postId

工作SQLFiddle

【讨论】:

    【解决方案3】:
    DECLARE @n INT = 3; -- or 10, or whatever
    
    ;WITH x AS
    (
        SELECT
            postid, commentdate,
            rn = ROW_NUMBER() OVER (ORDER BY commentdate DESC)
          FROM dbo.comment AS c
    ), y AS 
    (
      SELECT postid, rn = MIN(rn) FROM x
      GROUP BY postid
    )
    SELECT TOP (@n) p.postid, p.title, x.commentdate
    FROM x INNER JOIN y ON x.rn = y.rn
    INNER JOIN dbo.post AS p ON p.postid = x.postid
    ORDER BY x.commentdate DESC;
    

    或者稍微简单一点:

    DECLARE @n INT = 3; -- or 10, or whatever
    
    ;WITH x AS 
    (
        SELECT TOP (@n) postid, t = MAX(commentdate)
        FROM dbo.comment
        GROUP BY postid ORDER BY t DESC
    )
    SELECT p.postid, p.title, commentdate = x.t 
    FROM x INNER JOIN dbo.post AS p ON x.postid = p.postid
    ORDER BY x.t DESC;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-09
      • 2012-08-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多