Mysql
 sql >> Datenbank >  >> RDS >> Mysql

MYSQL-Abfrage - Holen Sie sich den neuesten Kommentar zum Beitrag

Diese Fehlermeldung

liegt typischerweise an der Definition Ihrer Spalten und Tabellen. Dies bedeutet normalerweise, dass auf beiden Seiten eines Gleichheitszeichens unterschiedliche Sortierungen vorhanden sind. Sie müssen nur eine auswählen und diese Entscheidung in Ihre Anfrage aufnehmen.

Das Kollationsproblem lag hier im CROSS JOIN von @prev_value, der eine explizite Kollatierung benötigte, um verwendet zu werden.

Ich habe auch die "row_number"-Logik leicht in einen einzelnen Kreuzjoin geändert und die if-Logik an die äußersten Enden der Auswahlliste verschoben.

Einige Beispieldaten werden unten angezeigt. Beispieldaten werden zum Testen von Abfragen benötigt. Jeder, der versucht, Ihre Frage mit funktionierenden Beispielen zu beantworten, benötigt Daten. Der Grund, warum ich es hier einfüge, ist zweierlei.

  1. damit Sie jedes von mir präsentierte Ergebnis verstehen werden
  2. damit Sie in Zukunft verstehen, wie wichtig es ist, Daten bereitzustellen, wenn Sie eine andere SQL-bezogene Frage stellen. Das ist nicht nur für uns bequemer. Wenn der Fragesteller die Beispieldaten bereitstellt, wird der Fragesteller sie bereits verstehen - es wird keine Erfindung eines Fremden sein, der einen Teil seiner Zeit darauf verwendet hat, zu helfen.

Beispieldaten

Bitte beachten Sie, dass einige Spalten in den Tabellen fehlen, es wurden nur die in den Tabellendetails angegebenen Spalten aufgenommen.

Diese Beispieldaten enthalten 5 Kommentare zu einem einzelnen Beitrag (es werden keine „Gefällt mir“-Angaben aufgezeichnet)

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-Standardverhalten:2 Zeilen pro Post-Abfrage]

Dies war meine erste Anfrage, mit einigen Korrekturen. Ich habe die Spaltenreihenfolge der Auswahlliste geändert, sodass Sie einige kommentarbezogene Daten leicht sehen können, wenn ich die Ergebnisse präsentiere. Bitte studieren Sie die bereitgestellten Ergebnisse, damit Sie verstehen, was die Abfrage bewirken wird. Spalten mit vorangestelltem # sind in den Beispieldaten, mit denen ich arbeite, aus Gründen, die ich bereits erwähnt habe, nicht vorhanden.

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
      ;
      
      

Siehe eine funktionierende Demonstration dieser Abfrage bei SQLFiddle

Ergebnisse :

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

Es gibt 2 REIHEN - wie erwartet. Eine Zeile für den neuesten Kommentar und eine weitere Zeile für den nächstneuesten Kommentar. Dies ist ein normales Verhalten für SQL und bis ein Kommentar unter dieser Antwort hinzugefügt wurde, würden die Leser der Frage davon ausgehen, dass dieses normale Verhalten akzeptabel wäre.

Der Frage fehlt ein klar artikuliertes "erwartetes Ergebnis".

[Option 1:Eine Zeile pro Post-Abfrage, mit BIS ZU 2 Kommentaren, hinzugefügten Spalten]

In einem Kommentar unten wurde offenbart, dass Sie keine 2 Zeilen pro Beitrag wollten und dies eine einfache Lösung wäre. Nun, es ist irgendwie einfach, ABER es gibt Optionen und die Optionen werden vom Benutzer in Form von Anforderungen diktiert. Wenn die Frage ein "erwartetes Ergebnis" hätte, wüssten wir, welche Option zu wählen ist. Nichtsdestotrotz ist hier eine Option

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
      ;

Siehe die zweite Abfrage, die bei SQLFiddle funktioniert

Ergebnisse von Abfrage 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 |

** Option 2, die neuesten Kommentare in einer einzigen, durch Kommas getrennten Liste verketten **

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
      

Siehe diese dritte Abfrage, die bei SQLFiddle funktioniert

Ergebnisse von Abfrage 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 |

** Zusammenfassung **

Ich habe 3 Abfragen präsentiert, jede zeigt nur die 2 neuesten Kommentare, aber jede Abfrage tut dies auf andere Weise. Die erste Abfrage (Standardverhalten) zeigt 2 Zeilen für jeden Beitrag an. Option 2 fügt eine Spalte hinzu, entfernt aber die zweite Zeile. Option 3 verkettet die 2 neuesten Kommentare.

Bitte beachten Sie Folgendes:

  • Der Frage fehlen Tabellendefinitionen, die alle Spalten abdecken
  • Der Frage fehlen Beispieldaten, was es für Sie schwieriger macht, die hier präsentierten Ergebnisse zu verstehen, aber auch für uns schwieriger, Lösungen vorzubereiten
  • Der Frage fehlt auch ein endgültiges "erwartetes Ergebnis" (das gewünschte Ergebnis), was zu einer weiteren Komplexität der Beantwortung geführt hat

Ich hoffe, dass die zusätzlichen bereitgestellten Informationen von Nutzen sind und dass Sie inzwischen auch wissen, dass es für SQL normal ist, Daten als mehrere Zeilen darzustellen. Wenn Sie dieses normale Verhalten nicht möchten, geben Sie bitte in Ihrer Frage genau an, was Sie wirklich wollen.

Nachschrift. Um eine weitere Unterabfrage für "folgt" einzufügen, können Sie eine ähnliche Unterabfrage wie die bereits vorhandene verwenden. Sie kann vor oder nach dieser Unterabfrage hinzugefügt werden. Sie können es auch bei sqlfiddle hier im Einsatz sehen

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

Während das Hinzufügen einer weiteren Unterabfrage Ihren Wunsch nach mehr Informationen beseitigen kann, kann die Gesamtabfrage proportional zum Wachstum Ihrer Daten langsamer werden. Sobald Sie sich für die Funktionalität entschieden haben, die Sie wirklich benötigen, kann es sich lohnen, darüber nachzudenken, welche Indizes Sie für diese Tabellen benötigen. (Ich glaube, Sie sollten diesen Rat separat anfordern, und wenn Sie dies tun, stellen Sie sicher, dass Sie 1. die vollständige DDL Ihrer Tabellen und 2. einen Erklärungsplan der Abfrage beifügen.)