Mysql
 sql >> Database >  >> RDS >> Mysql

Query MySQL:ottieni l'ultimo commento relativo al post

Questo messaggio di errore

è in genere dovuto alla definizione delle colonne e delle tabelle. Di solito significa che su entrambi i lati di un segno di uguale ci sono diverse regole di confronto. Quello che devi fare è sceglierne uno e includere tale decisione nella tua query.

Il problema delle regole di confronto qui era nel CROSS JOIN di @prev_value che necessitava di un confronto esplicito da utilizzare.

Ho anche leggermente modificato la logica "row_number" in un unico cross join e spostato la logica if agli estremi dell'elenco di selezione.

Di seguito vengono visualizzati alcuni dati di esempio. Sono necessari dati di esempio per testare le query. Chiunque tenti di rispondere alla tua domanda con esempi funzionanti avrà bisogno di dati. Il motivo per cui lo includo qui è duplice.

  1. in modo che tu possa capire qualsiasi risultato che presento
  2. in modo che in futuro, quando farai un'altra domanda relativa a SQL, capirai l'importanza di fornire dati. Non è solo più conveniente per noi che tu lo faccia. Se il richiedente fornisce i dati di esempio, il richiedente lo capirà già:non sarà un'invenzione di un estraneo che ha dedicato parte del proprio tempo per dare una mano.

Dati di esempio

Tieni presente che nelle tabelle mancano alcune colonne, sono state incluse solo le colonne specificate nei dettagli della tabella.

Questi dati di esempio hanno 5 commenti su un singolo post (non vengono registrati Mi piace)

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') ;

[Comportamento SQL Standard:2 righe per Post query]

Questa era la mia domanda iniziale, con alcune correzioni. Ho modificato l'ordine delle colonne dell'elenco di selezione in modo da visualizzare facilmente alcuni dati relativi ai commenti quando presento i risultati. Si prega di studiare i risultati che vengono forniti in modo da poter capire cosa farà la query. Le colonne precedute da # non esistono nei dati di esempio su cui sto lavorando per motivi che ho già notato.

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
      ;
      
      

Guarda una dimostrazione funzionante di questa query su SQLFiddle

Risultati :

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

Ci sono 2 RIGHE - come previsto. Una riga per il commento più recente e un'altra riga per il commento successivo più recente. Questo è un comportamento normale per SQL e fino a quando non viene aggiunto un commento in questa risposta, i lettori della domanda presumeranno che questo comportamento normale sarebbe accettabile.

La domanda manca di un "risultato atteso" chiaramente articolato.

[Opzione 1:una riga per query Post, con FINO A 2 commenti, colonne aggiunte]

In un commento qui sotto è stato rivelato che non volevi 2 righe per post e questa sarebbe una soluzione facile. Beh, in un certo senso è facile MA ci sono opzioni e le opzioni sono dettate dall'utente sotto forma di requisiti. SE la domanda avesse un "risultato atteso", allora sapremmo quale opzione scegliere. Tuttavia, ecco un'opzione

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
      ;

Guarda la seconda query che funziona su SQLFiddle

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

** Opzione 2, concatena i commenti più recenti in un unico elenco separato da virgole **

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
      

Guarda questa terza query che funziona su SQLFiddle

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

** Riepilogo **

Ho presentato 3 query, ognuna mostra solo i 2 commenti più recenti, ma ogni query lo fa in un modo diverso. La prima query (comportamento predefinito) visualizzerà 2 righe per ogni post. L'opzione 2 aggiunge una colonna ma rimuove la seconda riga. L'opzione 3 concatena i 2 commenti più recenti.

Si prega di notare che:

  • La domanda manca di definizioni di tabella che coprano tutte le colonne
  • La domanda è priva di dati di esempio, il che rende più difficile per te comprendere i risultati presentati qui, ma anche per noi è più difficile preparare soluzioni
  • La domanda manca anche di un "risultato atteso" definitivo (l'output desiderato) e questo ha portato a un'ulteriore complessità nella risposta

Spero che le informazioni aggiuntive fornite siano di qualche utilità e che ormai sappiate anche che è normale che SQL presenti i dati come più righe. Se non vuoi quel comportamento normale, sii specifico su ciò che vuoi veramente nella tua domanda.

Post scriptum. Per includere un'altra sottoquery per "folws" puoi usare una sottoquery simile a quella che hai già. Può essere aggiunto prima o dopo quella sottoquery. Puoi anche vederlo in uso su sqlfiddle qui

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

Sebbene l'aggiunta di un'altra sottoquery possa risolvere il tuo desiderio di ulteriori informazioni, la query complessiva potrebbe rallentare in proporzione alla crescita dei tuoi dati. Una volta stabilita la funzionalità di cui hai veramente bisogno, potrebbe valere la pena considerare di quali indici hai bisogno su quelle tabelle. (Credo che ti consigliamo di chiedere questo consiglio separatamente e se ti assicuri di includere 1. il DDL completo delle tue tabelle e 2. un piano esplicativo della query.)