MYSQL 查询 - 获取与帖子相关的最新评论

Posted

技术标签:

【中文标题】MYSQL 查询 - 获取与帖子相关的最新评论【英文标题】:MYSQL Query - Get latest comment related to the post 【发布时间】:2017-03-09 04:29:23 【问题描述】:

我正在尝试获取与我下载的每个帖子相关的最新 1 或 2 个 cmets,有点像 instagram 所做的,因为他们为每个帖子显示最新的 3 cmets,到目前为止,我正在获取帖子和点赞数。

现在我需要做的就是弄清楚如何获得最新的 cmets,不太确定如何接近它,这就是为什么我希望有更多专业知识的人可以帮助我!

这是我当前的查询:

(SELECT
        P.uuid,
        P.caption,
        P.imageHeight,
        P.path,
        P.date,
        U.id,
        U.fullname,
        U.coverImage,
        U.bio,
        U.username,
        U.profileImage,
        coalesce(Activity.LikeCNT,0),
        Activity.CurrentUserLiked
        FROM USERS AS U
        INNER JOIN Posts AS P 
        ON P.id = U.id
        LEFT JOIN (SELECT COUNT(DISTINCT Activity.uuidPost) LikeCNT, Activity.uuidPost, Activity.id, sum(CASE WHEN Activity.id = $id then 1 else 0 end) as CurrentUserLiked
        FROM Activity Activity
        WHERE type = 'like' 
        GROUP BY Activity.uuidPost) Activity
        ON Activity.uuidPost = P.uuid
        AND Activity.id = U.id
        WHERE U.id = $id)
UNION
        (SELECT 
        P.uuid,
        P.caption,
        P.imageHeight,
        P.path,
        P.date,
        U.id,
        U.fullname,
        U.coverImage,
        U.bio,
        U.username,
        U.profileImage,
        coalesce(Activity.LikeCNT,0),
        Activity.CurrentUserLiked
        FROM Activity AS A
        INNER JOIN USERS AS U 
        ON A.IdOtherUser=U.id
        INNER JOIN Posts AS P 
        ON P.id = U.id
        LEFT JOIN (SELECT COUNT(DISTINCT Activity.uuidPost) LikeCNT, Activity.uuidPost, Activity.id, sum(CASE WHEN Activity.id = $id then 1 else 0 end) as CurrentUserLiked
    FROM Activity Activity
    WHERE type = 'like' 
    GROUP BY Activity.uuidPost) Activity
    ON Activity.uuidPost = P.uuid
    AND Activity.id = U.id
    WHERE A.id = $id)
    ORDER BY date DESC
    LIMIT 0, 5

基本上cmets和likes存储在同一张表中。

所以表是Activity,那么我有一个列comment存储评论文本,然后“类型”等于“评论”。

可能解释得不是很好,但我愿意尝试提供尽可能多的细节!

如果有人能提供帮助,非常感谢!

更新

在https://***.com/users/1016435/xqbert 给出的这个查询中,我目前遇到了这个错误:

用于操作“=”的排序规则 (utf8_general_ci,IMPLICIT) 和 (utf8_unicode_ci,IMPLICIT) 的非法混合

SELECT Posts.id,
    Posts.uuid,
    Posts.caption,
    Posts.path,
    Posts.date,
    USERS.id,
    USERS.username,
    USERS.fullname,
    USERS.profileImage,
    coalesce(A.LikeCNT,0),
    com.comment
FROM Posts 
INNER JOIN USERS 
  ON Posts.id = 145 
 AND USERS.id = 145
LEFT JOIN (SELECT COUNT(A.uuidPost) LikeCNT, A.UUIDPost
    FROM Activity A
    WHERE type =  'like' 
    GROUP BY A.UUIDPOST) A
 on A.UUIDPost=Posts.uuid
LEFT JOIN (SELECT comment, UUIDPOST, @row_num := IF(@prev_value=UUIDPOST,@row_num+1,1) as row_number,@prev_value := UUIDPOST
           FROM Activity 
           CROSS JOIN (SELECT @row_num := 1) x
           CROSS JOIN (SELECT @prev_value := '') y
           WHERE type = 'comment'
           ORDER BY UUIDPOST, date DESC) Com
  ON Com.UUIIDPOSt = Posts.UUID
 AND row_number <= 2
ORDER BY date DESC
LIMIT 0, 5

最新编辑

表结构:

帖子

    ----------------------------------------------------------
    | id         | int(11)      |                 | not null |
    | uuid       | varchar(100) | utf8_unicode_ci | not null |
    | imageLink  | varchar(500) | utf8_unicode_ci | not null |
    | date       | timestamp    |                 | not null |
    ----------------------------------------------------------

用户

    -------------------------------------------------------------
    | id            | int(11)      |                 | not null |
    | username      | varchar(100) | utf8_unicode_ci | not null |
    | profileImage  | varchar(500) | utf8_unicode_ci | not null |
    | date          | timestamp    |                 | not null |
    -------------------------------------------------------------

活动

    ----------------------------------------------------------
    | id           | int(11)      |                 | not null |
    | uuid         | varchar(100) | utf8_unicode_ci | not null |
    | uuidPost     | varchar(100) | utf8_unicode_ci | not null |
    | type         | varchar(50)  | utf8_unicode_ci | not null |
    | commentText  | varchar(500) | utf8_unicode_ci | not null |
    | date         | timestamp    |                 | not null |
    ----------------------------------------------------------

这些是一些示例,在这种情况下,“活动”表中的“类型”将始终等于“评论”。

总结一切并渴望结果:

当我查询用户的帖子时,我希望能够进入“活动”表并为他的每个帖子获取最新 2 cmets。也许不会有 cmets,所以很明显它会返回 0,也许那个帖子可能有 100 个 cmets。但我只想获取最新/最近的 2 cmets。

一个例子可以看看 Instagram 是如何做到的。对于每个帖子,显示最近的 cmets 1、2 或 3....

希望这会有所帮助!

Fiddle link

【问题讨论】:

见meta.***.com/questions/333952/… 如果您在问题中包含表定义,将会得到很好的解释。 活动中的日期列的名称是什么?或者你如何确定最近的 1-2 cmets 是什么?)每个活动是否有唯一的序列,所以如果有,那么最高的 ID 是什么列名?或者是否有一个日期表示最近的活动,如果有,它的名称是什么? 请包含示例表数据和预期的查询输出。 请为每个相关表格提供SHOW CREATE TABLE 【参考方案1】:

我有点迷失在您的查询中,但是如果您想一次下载多个帖子的数据,那么在第一个查询中包含评论数据不是一个好主意,因为您将包含有关帖子和发布的所有数据用户多次。您应该运行另一个将帖子与 cmets 连接起来的查询。比如:

SELECT 
A.UUIDPost, 
C.username,
C.profileImage, 
B.Comment,
B.[DateField]
FROM Posts A JOIN 
Activities B ON A.uuid = B.UUIDPost JOIN
Users C ON B.[UserId] = C.id 

并使用该数据显示带有评论用户 ID、名称、图像等的 cmets。

每个帖子只能获得 3 cmets,您可以查看此帖子:

Select top 3 values from each group in a table with SQL

如果您确定评论表或此帖子中不会有重复的行:

How to select top 3 values from each group in a table with SQL which have duplicates

如果您对此不确定(尽管由于表中的 DateField,它应该是不可能的)。

【讨论】:

您好,非常感谢,我会调查的。我正在将此服务器用于我的 ios 应用程序,因此即使我同时需要所有这些数据,您也建议调用单独的查询? 如果您在主查询中包含评论数据,结果您将获得大约 15 个字段,其中 10 个字段对于每个帖子都是相同的,只有评论数据和评论用户的数据会发生变化。就我而言,这不是一个特别好的查询设计,从长远来看它可能是一个性能问题。 好的,非常感谢,我会告诉你我的进展情况 @Jack “真的想得到最好的答案”——但是反对什么?您的问题应该准确定义您想要什么然后我们提交解决它的想法。您正在通过一个不准确的问题来解决这个问题,并在检查答案时将新要求作为评论显示。 @maraca 我同意,我确实缺乏经验,这就是我努力学习的原因。我敢肯定,你也曾一度处于同样的境地。没有必要拒绝我的问题,这一切都是因为我决定接受 User_By_Already 的回答。在我告诉你我接受了他的回答之后,我突然投了反对票。即使您的回答确实有效,我也不会接受,因为 OP 在这方面付出了比您更多的努力。我不只是在寻找一个可行的解决方案,而且似乎是最好的......我可以向你保证,他的答案看起来更充分。即使我“缺乏经验”,我也能看到这一点。【参考方案2】:

这种类型的评论已经发布了很多次,试图获得“每个人都最新”似乎总是一个绊脚石,并且对大多数人来说是加入/子查询的噩梦。

尤其是对于 Web 界面,您最好将一列(或 2 或 3)添加到作为您的活动“帖子”表的一个表中,例如 Latest1、Latest2、Latest3。

然后,通过插入到您的评论表中,在您的表上设置一个插入触发器,以使用最新的 ID 更新主帖子。然后,您始终在表上拥有该 ID,而没有任何子连接。现在,正如您所提到的,您可能希望拥有最后 2 个或 3 个 ID,然后添加 3 个示例列并让您的插入触发器到帖子评论详细信息对主帖子表进行更新,例如

update PrimaryPostTable
   set Latest3 = Latest2,
       Latest2 = Latest1,
       Latest1 = NewDetailCommentID
   where PostID = PostIDFromTheInsertedDetail

这必须在 mysql 下被形式化为适当的触发器,但应该很容易实现。您可以使用最新的 1 来填充列表,然后随着新帖子的发布,它会自动将最新的帖子滚动到他们的第 1、第 2、第 3 位置。最后,您的查询可以简化为类似

Select
      P.PostID,
      P.TopicDescription,
      PD1.WhateverDetail as LatestDetail1,
      PD2.WhateverDetail as LatestDetail2,
      PD3.WhateverDetail as LatestDetail3
   from
      Posts P
         LEFT JOIN PostDetail PD1
            on P.Latest1 = PD1.PostDetailID
         LEFT JOIN PostDetail PD2
            on P.Latest2 = PD2.PostDetailID
         LEFT JOIN PostDetail PD3
            on P.Latest3 = PD3.PostDetailID
   where
      whateverCondition

通常不需要非规范化数据。但是,在这种情况下,在 For-Each 类型的查询中获取这些“最新”条目是一个很好的简化方法。祝你好运。

这是 MySQL 中的一个完整工作示例,因此您可以查看表和 sql-inserts 的结果以及通过触发器自动标记以更新主 post 表。然后查询 post 表,您可以看到最新的如何自动滚动到第一、第二和第三位置。最后一个显示如何从每个“发布活动”中提取所有数据的连接

CREATE TABLE Posts
(   id int, 
    uuid varchar(7),
    imageLink varchar(9),
    `date` datetime,
    ActivityID1 int null,
    ActivityID2 int null,
    ActivityID3 int null,
    PRIMARY KEY (id)
);

CREATE TABLE Activity
(   id int, 
    postid int,
    `type` varchar(40) collate utf8_unicode_ci, 
    commentText varchar(20) collate utf8_unicode_ci, 
    `date` datetime,
    PRIMARY KEY (id)
);

DELIMITER //

CREATE TRIGGER ActivityRecAdded
AFTER INSERT ON Activity FOR EACH ROW
BEGIN
    Update Posts
        set ActivityID3 = ActivityID2,
            ActivityID2 = ActivityID1,
            ActivityID1 = NEW.ID
        where
            ID = NEW.POSTID;

END; //

DELIMITER ;



INSERT INTO Posts
    (id, uuid, imageLink, `date`)
    VALUES
    (123, 'test1', 'blah', '2016-10-26 00:00:00');

INSERT INTO Posts
    (id, uuid, imageLink, `date`)
    VALUES
    (125, 'test2', 'blah 2', '2016-10-26 00:00:00');


INSERT INTO Activity
    (id, postid, `type`, `commentText`, `date`)
VALUES
    (789, 123, 'type1', 'any comment', '2016-10-26 00:00:00'),
    (821, 125, 'type2', 'another comment', '2016-10-26 00:00:00'),
    (824, 125, 'type3', 'third comment', '2016-10-27 00:00:00'),
    (912, 123, 'typeAB', 'comment', '2016-10-27 00:00:00');

-- See the results after the insert and the triggers.
-- you will see that the post table has been updated with the 
-- most recent 
-- activity post ID=912 in position Posts.Activity1
-- activity post ID=789 in position Posts.Activity2
-- no value in position Posts.Activity3
select * from Posts;

-- NOW, insert two more records for post ID = 123.
-- you will see the shift of ActivityIDs adjusted
INSERT INTO Activity
    (id, postid, `type`, `commentText`, `date`)
VALUES
    (931, 123, 'type1', 'any comment', '2016-10-28 00:00:00'),
    (948, 123, 'newest', 'blah', '2016-10-29 00:00:00');

-- See the results after the insert and the triggers.
-- you will see that the post table has been updated with the 
-- most recent 
-- activity post ID=948 in position Posts.Activity1
-- activity post ID=931 in position Posts.Activity2
-- activity post ID=912 in position Posts.Activity3
-- notice the FIRST activity post 789 is not there as 
-- anything AFTER the 4th entry, it got pushed away.
select * from Posts;

-- Finally, query the data to get the most recent 3 items for each post.
select
        p.id,
        p.uuid,
        p.imageLink,
        p.`date`,
        A1.id NewestActivityPostID,
        A1.`type` NewestType,
        A1.`date` NewestDate,
        A2.id SecondActivityPostID,
        A2.`type` SecondType,
        A2.`date` SecondDate,
        A3.id ThirdActivityPostID,
        A3.`type` ThirdType,
        A3.`date` ThirdDate
    from
        Posts p
            left join Activity A1
                on p.ActivityID1 = A1.ID
            left join Activity A2
                on p.ActivityID2 = A2.ID
            left join Activity A3
                on p.ActivityID3 = A3.ID;

您可以创建一个测试数据库以免损坏您的数据库以查看此示例。

【讨论】:

好的,非常感谢您的时间和答案。我会让你知道我是怎么过的以及我决定做什么 嗨 DRapp,真的想得到最好的答案,这就是我添加赏金的原因。我没有完全得到你的答案,但我已经在上面编辑了我的问题,所以也许它更容易理解我想要实现的目标! @Jack,用创建表、插入触发器和显示最近 3 个帖子活动的最终结果的完整示例修改了我的答案。您可以更改表名以不影响您的生产数据,或创建一个临时辅助数据库进行测试。如果需要,我可以进行更多调整,例如给定帖子的总活动记录,只需添加另一列并在每次插入期间添加 1。【参考方案3】:

未经测试:我建议将SQL fiddle 与一些示例数据和显示问题的现有表结构放在一起;这样我们就可以处理响应并确保您的架构具有功能。

所以我们用一个变量来模拟一个窗口函数(比如row_number)

在这种情况下@Row_num 和@prev_Value。 @Row_number 跟踪每个帖子的当前行(因为单个帖子可能有很多 cmets)然后当遇到新的帖子 ID(UUIDPOST?)时 row_num 变量重置为 1。当当前记录 UUIDPOST 匹配变量@prev_Value,我们只需将行增加1。

此技术允许我们根据日期或活动 ID 降序分配行号。由于每个交叉连接仅产生 1 条记录,因此我们不会导致出现重复记录。但是,由于我们随后通过 row_number

这假设帖子与用户的关系是多对一的,这意味着帖子只能有 1 个用户。

类似这样:虽然我不确定最终的左连接,但我需要更好地理解活动表的结构,因此对原始问题进行评论。

SELECT Posts.id,
        Posts.uuid,
        Posts.caption,
        Posts.path,
        Posts.date,
        USERS.id,
        USERS.username,
        USERS.fullname,
        USERS.profileImage,
        coalesce(A.LikeCNT,0)
        com.comment
    FROM Posts 
    INNER JOIN USERS 
      ON Posts.id = 145 
     AND USERS.id = 145
    LEFT JOIN (SELECT COUNT(A.uuidPost) LikeCNT, A.UUIDPost
        FROM Activity A
        WHERE type =  'like' 
        GROUP BY A.UUIDPOST) A
     on A.UUIDPost=Posts.uuid


  --This join simulates row_Number() over (partition by PostID, order by activityID desc)  (Nice article [here](http://preilly.me/2011/11/11/mysql-row_number/) several other examples exist on SO already.
   --Meaning.... Generate a row number for each activity from 1-X restarting at 1 for each new post but start numbering at the newest activityID)

    LEFT JOIN (SELECT comment, UUIDPOST, @row_num := IF(@prev_value=UUIDPOST,@row_num+1,1) as row_number,@prev_value := UUIDPOST

               FROM ACTIVITY 
               CROSS JOIN (SELECT @row_num := 1) x
               CROSS JOIN (SELECT @prev_value := '') y
               WHERE type = 'comment'
               ORDER BY UUIDPOST, --Some date or ID desc) Com
       on Com.UUIIDPOSt = Posts.UUID
       and row_number < = 2


  -- Now since we have a row_number restarting at 1 for each new post, simply return only the 1st two rows.

    ORDER BY date DESC
    LIMIT 0, 5

我们必须将 and row_number

此外,我们可能应该查看“comment”字段以确保它不是空白或 null,但首先要确保它有效。

【讨论】:

哇,不得不说这是一个很好的答案,只是测试了它并将“--Some date or ID desc”更改为 ORDER BY date DESC(不确定这是否正确)。但是现在我收到此错误:“您的 SQL 语法有错误;请查看与您的 MySQL 服务器版本相对应的手册,以获取在 'CROSS JOIN (SELECT @prev_value := 1) y WHERE type = ' 附近使用的正确语法评论'" 您是否删除了评论块--?看来我有一个额外的逗号。我想要一个 SQL 小提琴的真正原因是,我可以调试我写的东西来消除这种类型的来回:P 哦,在 corss join () x 之后没有逗号, 是的,删除了我将添加到目前为止的评论块。我会尝试制作一个 SQL 小提琴......从来没有使用过它,所以不知道该怎么做,但我会尝试 您可以将所需的 3 个表(和字段)的创建表语句与一些插入语句一起放置。从那里我们可以修改 SQL 直到它是你所追求的(其他有想法的人也可以玩弄它以确保它产生你所追求的数据集! 嗯,尝试做起来并不顺利...你介意我需要一点时间吗?【参考方案4】:

这个错误信息

排序规则的非法混合 (utf8_general_ci,IMPLICIT) 和 (utf8_unicode_ci,IMPLICIT) 用于操作“=”

通常是由于您的列和表的定义。这通常意味着在等号的两边都有不同的排序规则。您需要做的是选择一个并将该决定包含在您的查询中。

这里的排序规则问题出现在 @prev_value 的 CROSS JOIN 中,需要使用显式排序规则。

我还稍微将“row_number”逻辑更改为单个交叉连接,并将 if 逻辑移动到选择列表的极端。

下面显示了一些示例数据。需要样本数据来测试查询。任何试图用工作示例回答您的问题的人都需要数据。我在这里包含它的原因是双重的。

    以便您了解我提供的任何结果 因此,当您将来提出另一个与 SQL 相关的问题时,您就会了解提供数据的重要性。您这样做不仅对我们更方便。如果提问者提供了样本数据,那么提问者就已经理解了——这不会是某个花时间提供帮助的陌生人的发明。

样本数据

请注意表格中缺少某些列,仅包含表格详细信息中指定的列。

此示例数据针对单个帖子有 5 个 cmets(不记录点赞)

CREATE TABLE Posts 
(
`id` int, 
`uuid` varchar(7) collate utf8_unicode_ci,
`imageLink` varchar(9) collate utf8_unicode_ci, 
`date` datetime
 );
    
INSERT INTO Posts(`id`, `uuid`, `imageLink`, `date`)
VALUES
(145, 'abcdefg', 'blah blah', '2016-10-10 00:00:00') ;

CREATE TABLE   USERS
(
`id` int, 
`username` varchar(15) collate utf8_unicode_ci,
 `profileImage` varchar(12) collate utf8_unicode_ci,
 `date` datetime
) ;
        
INSERT INTO     USERS(`id`, `username`, `profileImage`, `date`)
VALUES
(145, 'used_by_already', 'blah de blah', '2014-01-03 00:00:00') ;
    
    
CREATE TABLE Activity
(
`id` int, 
`uuid` varchar(4) collate utf8_unicode_ci, 
`uuidPost` varchar(7) collate utf8_unicode_ci,
 `type` varchar(40) collate utf8_unicode_ci, 
`commentText` varchar(11) collate utf8_unicode_ci, `date` datetime
) ;
        
INSERT INTO Activity (`id`, `uuid`, `uuidPost`, `type`, `commentText`, `date`)
 VALUES
(345, 'a100', 'abcdefg', 'comment', 'lah lha ha', '2016-07-05 00:00:00'),
(456, 'a101', 'abcdefg', 'comment', 'lah lah lah', '2016-07-06 00:00:00'),
(567, 'a102', 'abcdefg', 'comment', 'lha lha ha', '2016-07-07 00:00:00'),
(678, 'a103', 'abcdefg', 'comment', 'ha lah lah', '2016-07-08 00:00:00'),
(789, 'a104', 'abcdefg', 'comment', 'hla lah lah', '2016-07-09 00:00:00') ;

[SQL 标准行为:每个 Post 查询 2 行]

这是我最初的查询,有一些更正。我更改了选择列表的列顺序,以便在我呈现结果时您可以轻松看到一些评论相关数据。请研究它们提供的结果,以便您了解查询的作用。由于我已经指出的原因,我正在使用的示例数据中不存在以 # 开头的列。

SELECT
      Posts.id
    , Posts.uuid
    , rcom.uuidPost
    , rcom.commentText
    , rcom.`date` commentDate 
    #, Posts.caption
    #, Posts.path
    , Posts.`date`
    , USERS.id
    , USERS.username
    #, USERS.fullname
    , USERS.profileImage
    , COALESCE(A.LikeCNT, 0) num_likes
FROM Posts
INNER JOIN USERS ON Posts.id = 145
            AND USERS.id = 145
LEFT JOIN (
          SELECT
                COUNT(A.uuidPost) LikeCNT
              , A.UUIDPost
          FROM Activity A
          WHERE type = 'like'
          GROUP BY
                A.UUIDPOST
          ) A ON A.UUIDPost = Posts.uuid 
LEFT JOIN (
      SELECT
            @row_num := IF(@prev_value=UUIDPOST,@row_num+1,1) as row_number
          , commentText
          , uuidPost
          , `date`
          , @prev_value := UUIDPOST
      FROM Activity
      CROSS JOIN ( SELECT @row_num := 1, @prev_value := '' collate utf8_unicode_ci  ) xy
      WHERE type = 'comment'
      ORDER BY
            uuidPost
          , `date` DESC
      ) rcom ON rcom.uuidPost  = Posts.UUID
            AND rcom.row_number <= 2
ORDER BY
      posts.`date` DESC
      ;
      
      

See a working demonstration of this query at SQLFiddle

Results

|  id |    uuid | uuidPost | commentText |                   date |                      date |  id |        username | profileImage | num_likes |
|-----|---------|----------|-------------|------------------------|---------------------------|-----|-----------------|--------------|-----------|
| 145 | abcdefg |  abcdefg | hla lah lah | July, 09 2016 00:00:00 | October, 10 2016 00:00:00 | 145 | used_by_already | blah de blah |         0 |
| 145 | abcdefg |  abcdefg |  ha lah lah | July, 08 2016 00:00:00 | October, 10 2016 00:00:00 | 145 | used_by_already | blah de blah |         0 |

有 2 行 - 正如预期的那样。一行用于最新评论,另一行用于下一条最新评论。这是 SQL 的正常行为,在此答案下添加评论之前,问题的读者会认为这种正常行为是可以接受的。

这个问题缺乏清晰的“预期结果”。


[选项 1:每个 Post 查询一行,最多 2 个 cmets,添加列]

在下面的评论中显示,您不希望每个帖子有 2 行,这将是一个简单的解决方法。嗯,这很容易,但有一些选项,选项由用户以需求的形式决定。如果问题有“预期结果”,那么我们就会知道选择哪个选项。尽管如此,这是一种选择

SELECT
      Posts.id
    , Posts.uuid
    , max(case when rcom.row_number = 1 then rcom.commentText end) Comment_one
    , max(case when rcom.row_number = 2 then rcom.commentText end) Comment_two
    #, Posts.caption
    #, Posts.path
    , Posts.`date`
    , USERS.id
    , USERS.username
    #, USERS.fullname
    , USERS.profileImage
    , COALESCE(A.LikeCNT, 0) num_likes
FROM Posts
INNER JOIN USERS ON Posts.id = 145
            AND USERS.id = 145
LEFT JOIN (
          SELECT
                COUNT(A.uuidPost) LikeCNT
              , A.UUIDPost
          FROM Activity A
          WHERE type = 'like'
          GROUP BY
                A.UUIDPOST
          ) A ON A.UUIDPost = Posts.uuid 
LEFT JOIN (
      SELECT
            @row_num := IF(@prev_value=UUIDPOST,@row_num+1,1) as row_number
          , commentText
          , uuidPost
          , `date`
          , @prev_value := UUIDPOST
      FROM Activity
      CROSS JOIN ( SELECT @row_num := 1, @prev_value := '' collate utf8_unicode_ci  ) xy
      WHERE type = 'comment'
      ORDER BY
            uuidPost
          , `date` DESC
      ) rcom ON rcom.uuidPost  = Posts.UUID
            AND rcom.row_number <= 2
GROUP BY
      Posts.id
    , Posts.uuid
    #, Posts.caption
    #, Posts.path
    , Posts.`date`
    , USERS.id
    , USERS.username
    #, USERS.fullname
    , USERS.profileImage
    , COALESCE(A.LikeCNT, 0)
ORDER BY
      posts.`date` DESC
      ;

See the second query working at SQLFiddle

Results of query 2

|  id |    uuid | Comment_one | Comment_two |                      date |  id |        username | profileImage | num_likes |
|-----|---------|-------------|-------------|---------------------------|-----|-----------------|--------------|-----------|
| 145 | abcdefg | hla lah lah |  ha lah lah | October, 10 2016 00:00:00 | 145 | used_by_already | blah de blah |         0 |

** 选项 2,将最近的 cmets 连接到一个逗号分隔列表中 **

SELECT
      Posts.id
    , Posts.uuid
    , group_concat(rcom.commentText) Comments_two_concatenated
    #, Posts.caption
    #, Posts.path
    , Posts.`date`
    , USERS.id
    , USERS.username
    #, USERS.fullname
    , USERS.profileImage
    , COALESCE(A.LikeCNT, 0) num_likes
FROM Posts
INNER JOIN USERS ON Posts.id = 145
            AND USERS.id = 145
LEFT JOIN (
          SELECT
                COUNT(A.uuidPost) LikeCNT
              , A.UUIDPost
          FROM Activity A
          WHERE type = 'like'
          GROUP BY
                A.UUIDPOST
          ) A ON A.UUIDPost = Posts.uuid 
LEFT JOIN (
      SELECT
            @row_num := IF(@prev_value=UUIDPOST,@row_num+1,1) as row_number
          , commentText
          , uuidPost
          , `date`
          , @prev_value := UUIDPOST
      FROM Activity
      CROSS JOIN ( SELECT @row_num := 1, @prev_value := '' collate utf8_unicode_ci  ) xy
      WHERE type = 'comment'
      ORDER BY
            uuidPost
          , `date` DESC
      ) rcom ON rcom.uuidPost  = Posts.UUID
            AND rcom.row_number <= 2
GROUP BY
      Posts.id
    , Posts.uuid
    #, Posts.caption
    #, Posts.path
    , Posts.`date`
    , USERS.id
    , USERS.username
    #, USERS.fullname
    , USERS.profileImage
    , COALESCE(A.LikeCNT, 0)
ORDER BY
      posts.`date` DESC
      

See this third query working at SQLFiddle

Results of query 3

|  id |    uuid | Comments_two_concatenated |                      date |  id |        username | profileImage | num_likes |
|-----|---------|---------------------------|---------------------------|-----|-----------------|--------------|-----------|
| 145 | abcdefg |    hla lah lah,ha lah lah | October, 10 2016 00:00:00 | 145 | used_by_already | blah de blah |         0 |

** 总结**

我提出了 3 个查询,每个查询仅显示 2 个最近的 cmets,但每个查询以不同的方式执行此操作。第一个查询(默认行为)将为每个帖子显示 2 行。选项 2 添加一列但删除第二行。选项 3 连接 2 个最近的 cmets。

请注意:

该问题缺少涵盖所有列的表定义 该问题缺少任何示例数据,这使您更难理解此处提供的任何结果,也使我们更难准备解决方案 这个问题也缺乏明确的“预期结果”(想要的输出),这导致回答更加复杂

我确实希望额外提供的信息会有一些用处,而且现在您也知道 SQL 将数据显示为多行是正常的。如果您不希望出现这种正常行为,请具体说明您在问题中真正想要的是什么。


后记。要包含另一个“关注”子查询,您可以使用与您已有的子查询类似的子查询。它可以在该子查询之前或之后添加。你也可以在 sqlfiddle here看到它的使用情况@

LEFT JOIN (
          SELECT
                COUNT(*) FollowCNT
              , IdOtherUser
          FROM Activity
          WHERE type = 'Follow'
          GROUP BY
                IdOtherUser
          ) F ON USERS.id = F.IdOtherUser

虽然添加另一个子查询可能会满足您对更多信息的需求,但整体查询可能会随着数据的增长而变慢。一旦确定了您真正需要的功能,可能值得考虑在这些表上需要哪些索引。 (我相信您会被建议单独询问该建议,并且如果您确实确保包含 1. 表的完整 DDL 和 2. 查询的解释计划。)

【讨论】:

您好,感谢您的回答!在尝试您的代码后,我目前得到这个:您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以在 'collat​​ion utf8_general_ci LEFT JOIN ( SELECT @row_num := IF(@p' at line 24) 附近使用正确的语法 我已经更新了我的问题...也许它更好地解释了我的要求! 对不起,我应该使用 COLLATE 而不是排序规则。我更新了查询。 这个错误再次出现:非法混合排序规则(utf8_general_ci,IMPLICIT)和(utf8_unicode_ci,IMPLICIT)操作'=' 我不使用 Instagram,所以这不是一个有用的解释。真的,我相信我们已经到了我说够了就够了的地步。请再问一个问题。确保您在该问题中包含足够的信息以获得答案;提供样本数据 + 提供预期结果【参考方案5】:

这可能会摆脱非法的排序规则混合......在建立连接之后,执行这个查询:

SET NAMES utf8 COLLATE utf8_unicode_ci;

关于'latest 2'的问题,请使用mysql命令行工具运行SHOW CREATE TABLE Posts并提供输出。 (其他相关表同上。)phpmyadmin(和其他 UI)有一种方法可以在不进入命令行的情况下执行查询。

【讨论】:

【参考方案6】:

您可以使用子查询通过一个非常简单的查询到达那里。首先,我在 where 子句中指定用户并加入帖子,因为这对我来说似乎更符合逻辑。然后我得到所有喜欢的帖子都有一个子查询。

现在,我们通过限制当前查看日期之后的日期计数,仅加入我们想要的值,而不是分组和限制组大小。

如果您只想显示包含至少一条评论的帖子,请使用 INNER JOIN 活动。

SELECT
  u.id,
  u.username,
  u.fullname,
  u.profileImage,
  p.uuid,
  p.caption,
  p.path,
  p.date,
  (SELECT COUNT(*) FROM Activity v WHERE v.uuidPost = p.uuidPost AND v.type = 'like') likes,
  a.commentText,
  a.date
FROM
  Users u INNER JOIN
  Posts p ON p.id = u.id LEFT JOIN
  Activity a ON a.uuid = p.uuid AND a.type = 'comment' AND 2 > (
    SELECT COUNT(*) FROM Activity v
    WHERE v.uuid = p.uuid AND v.type = 'comment' AND v.date > a.date)
WHERE
  u.id = 145


也就是说,重新设计可能是最好的,而且在性能方面也是如此(Activity 很快就会包含很多条目,并且它们总是必须针对所需的类型进行过滤)。用户表可以使用 id 自动递增并作为主键。对于帖子,我还将添加一个自动递增的 id 作为主键,将 user_id 添加为外键(您还可以决定删除时要做什么,例如,通过级联,他的所有帖子也将被自动删除)。

对于 cmets 和 likes,您可以使用两个外键 user_id 和 post_id 创建单独的表(简单示例,像这样,您只能喜欢帖子而没有其他内容,但如果没有很多不同类型的喜欢,它仍然可以是最好创建一个 post_likes 和其他几个 ..._likes 表,您必须考虑通常如何查询这些数据,如果这些喜欢大多相互独立,那可能是一个不错的选择)。

【讨论】:

您好,感谢您的关注,我收到了这个错误 #1064 - 您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以在第 5 行的 '.profileImage, p.uuid, p.caption, p.path, p.date, (SELECT COUNT(*) FRO' 附近使用正确的语法跨度> 忘记我说的...只是一个逗号 ;-)(在全名之后,现在更正)。 此 URL 可能会有所帮助 sqlfiddle.com/#!9/6b983/1 请注意此查询每个帖子返回 2 行 @Used_By_Already,我将删除有关 DBMS 的 cmets。是的,每个帖子最多 2 行是我认为他想要得到的。 不起作用,它显示了列等,但没有 cmets...而且@Used_By_Already 已经为我排序了。

以上是关于MYSQL 查询 - 获取与帖子相关的最新评论的主要内容,如果未能解决你的问题,请参考以下文章

Django ORM:在不执行 N+1 查询的情况下检索帖子和最新评论

SQL 获取帖子的最新评论日期 - 论坛

缓存 MySQL 中排序所需的聚合?

MYSQL Join - 父子表连接,只获取子表的最新记录

如何在我的博客网站顶部显示最新帖子和评论?

如何使用实体框架和 MySQL 获取每个组的最新记录,包括相关实体