sql >> Databasteknik >  >> RDS >> Mysql

MYSQL-fråga - Få senaste kommentar relaterad till inlägget

Detta felmeddelande

beror vanligtvis på definitionen av dina kolumner och tabeller. Det betyder vanligtvis att det finns olika sammanställningar på båda sidor om ett likhetstecken. Vad du behöver göra är att välja ett och inkludera det beslutet i din fråga.

Sorteringsproblemet här var i CROSS JOIN av @prev_value som behövde en explicit sortering för att användas.

Jag har också ändrat "row_number"-logiken något till en enda korskoppling och flyttat if-logiken till ytterligheterna av den valda listan.

Några exempeldata visas nedan. Exempeldata behövs för att testa frågor med. Alla som försöker svara på din fråga med fungerande exempel kommer att behöva data. Anledningen till att jag tar med den här är tvåfaldig.

  1. så att du förstår alla resultat jag presenterar
  2. så att du i framtiden förstår vikten av att tillhandahålla data när du ställer en annan SQL-relaterad fråga. Det är inte bara bekvämare för oss att du gör detta. Om frågeställaren tillhandahåller exempeldata kommer frågeställaren redan att förstå det – det kommer inte att vara en uppfinning av någon främling som har ägnat en del av sin tid åt att hjälpa till.

Exempeldata

Observera att vissa kolumner saknas i tabellerna, endast de kolumner som anges i tabelldetaljerna har tagits med.

Denna exempeldata har 5 kommentarer mot ett enda inlägg (inga likes registreras)

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 standardbeteende:2 rader per inläggsfråga]

Detta var min första fråga, med några korrigeringar. Jag ändrade kolumnordningen i urvalslistan så att du enkelt kan se några kommentarsrelaterade data när jag presenterar resultaten. Vänligen studera resultaten de tillhandahålls så att du kanske förstår vad frågan kommer att göra. Kolumner som föregås av # finns inte i exempeldatan jag arbetar med av skäl som jag redan har noterat.

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
      ;
      
      

Se en fungerande demonstration av den här frågan på SQLFiddle

Resultat :

|  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 |

Det finns 2 RADER - som förväntat. En rad för den senaste kommentaren och en annan rad för den näst senaste kommentaren. Detta är normalt beteende för SQL och tills en kommentar lades till under detta svar skulle läsare av frågan anta att detta normala beteende skulle vara acceptabelt.

Frågan saknar ett tydligt formulerat "förväntat resultat".

[Alternativ 1:En rad per inläggsfråga, med UPP TILL 2 kommentarer, tillagda kolumner]

I en kommentar nedan avslöjades att du inte ville ha 2 rader per inlägg och detta skulle vara en enkel lösning. Tja, det är liksom enkelt MEN det finns alternativ och alternativen dikteras av användaren i form av krav. OM frågan fick ett "förväntat resultat" så skulle vi veta vilket alternativ vi skulle välja. Här är dock ett alternativ

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
      ;

Se den andra frågan som fungerar på SQLFiddle

Resultat av fråga 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 |

** Alternativ 2, sammanfoga de senaste kommentarerna till en enda kommaseparerad lista **

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
      

Se den här tredje frågan som fungerar på SQLFiddle

Resultat av fråga 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 |

** Sammanfattning **

Jag har presenterat 3 frågor, var och en visar bara de 2 senaste kommentarerna, men varje fråga gör det på ett annat sätt. Den första frågan (standardbeteende) kommer att visa 2 rader för varje inlägg. Alternativ 2 lägger till en kolumn men tar bort den andra raden. Alternativ 3 sammanfogar de 2 senaste kommentarerna.

Observera att:

  • Frågan saknar tabelldefinitioner som täcker alla kolumner
  • Frågan saknar exempeldata, vilket gör det svårare för dig att förstå eventuella resultat som presenteras här, men också svårare för oss att förbereda lösningar
  • Frågan saknar också ett definitivt "förväntat resultat" (det önskade resultatet) och detta har lett till ytterligare komplexitet i svaret

Jag hoppas att den ytterligare informationen kommer att vara till någon nytta, och att du vid det här laget också vet att det är normalt för SQL att presentera data som flera rader. Om du inte vill ha det normala beteendet var vänlig var specifik om vad du verkligen vill ha i din fråga.

Postskriptum. För att inkludera ytterligare en underfråga för "följer" kan du använda en liknande underfråga som den du redan har. Den kan läggas till före eller efter den underfrågan. Du kan också se den användas på sqlfiddle här

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

Även om du lägger till ytterligare en underfråga kan lösa din önskan om mer information, men den övergripande frågan kan bli långsammare i proportion till din datatillväxt. När du väl har bestämt dig för den funktionalitet du verkligen behöver kan det vara värt att överväga vilka index du behöver på dessa bord. (Jag tror att du skulle rekommenderas att be om det rådet separat, och om du gör det, se till att du inkluderar 1. hela DDL för dina tabeller och 2. en förklarande plan för frågan.)



  1. Installera exempelscheman för Oracle 12c med hjälp av Database Configuration Assistant

  2. Hur avgör man vilken typ av index som ska användas i Postgres?

  3. Hur räknar man rader från två tabeller i en fråga?

  4. Att använda utf8 eller inte - MySQL- och PHP-teckenkodningsproblem