MYSQL Query - Get latest comment related to the post

前端 未结 6 1032
刺人心
刺人心 2021-01-11 20:38

I am trying to get the latest 1 or 2 comments related to each post I download, a bit like instagram does as they show the latest 3 comments for each post, So far I am gettin

6条回答
  •  时光取名叫无心
    2021-01-11 21:15

    This type of comment has been posted many times, and trying to get the "latest-for-each" always appears to be a stumbling block and join / subquery nightmare for most.

    Especially for a web interface, you might be better to tack on a column (or 2 or 3) to the one table that is your active "posts" table such as Latest1, Latest2, Latest3.

    Then, via an insert into your comment table, have an insert trigger on your table to update the main post with the newest ID. Then you always have that ID on the table without any sub-joins. Now, as you mentioned, you might want to have the last 2 or 3 IDs, then add the 3 sample columns and have your insert trigger to the post comment detail do an update to the primary post table something like

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

    This would have to be formalized into a proper trigger under MySQL, but should be easy enough to implement. You could prime the list with the latest 1, then as new posts go, it would automatically roll the most recent into their 1st, 2nd, 3rd positions. Finally your query could be simplified down to something like

    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
    

    Denormalizing data is typically NOT desired. However, in cases such as this, it is a great simplifier for getting these "latest" entries in a For-Each type of query. Good luck.

    Here is a fully working sample in MySQL so you can see the tables and the results of the sql-inserts and the automatic stamping via the trigger to update the main post table. Then querying the post table you can see how the most recent automatically rolls into first, second and third positions. Finally a join showing how to pull all the data from each "post activity"

    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;
    

    You can create a test database as to not corrupt yours to see this example.

提交回复
热议问题