Mysql
 sql >> Base de données >  >> RDS >> Mysql

MYSQL Query - Obtenez le dernier commentaire lié à la publication

Ce message d'erreur

est généralement dû à la définition de vos colonnes et tables. Cela signifie généralement que de chaque côté d'un signe égal, il y a différentes collations. Ce que vous devez faire, c'est en choisir un et inclure cette décision dans votre requête.

Le problème de classement ici était dans le CROSS JOIN de @prev_value qui nécessitait l'utilisation d'un classement explicite.

J'ai également légèrement changé la logique "row_number" en une seule jointure croisée et déplacé la logique if aux extrêmes de la liste de sélection.

Quelques exemples de données sont affichés ci-dessous. Des exemples de données sont nécessaires pour tester les requêtes. Quiconque tente de répondre à votre question avec des exemples concrets aura besoin de données. La raison pour laquelle je l'inclus ici est double.

  1. pour que vous compreniez tout résultat que je présente
  2. pour qu'à l'avenir, lorsque vous poserez une autre question liée à SQL, vous compreniez l'importance de fournir des données. Ce n'est pas seulement plus pratique pour nous que vous le fassiez. Si le demandeur fournit l'exemple de données, il le comprendra déjà - ce ne sera pas une invention d'un inconnu qui a consacré une partie de son temps à aider.

Exemple de données

Veuillez noter que certaines colonnes manquent dans les tableaux, seules les colonnes spécifiées dans les détails du tableau ont été incluses.

Cet exemple de données contient 5 commentaires sur un seul message (aucun "J'aime" n'est enregistré)

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

[Comportement SQL standard :2 lignes par requête Post]

C'était ma première requête, avec quelques corrections. J'ai changé l'ordre des colonnes de la liste de sélection afin que vous puissiez voir facilement certaines données liées aux commentaires lorsque je présenterai les résultats. Veuillez étudier les résultats fournis afin de comprendre ce que la requête fera. Les colonnes précédées de # n'existent pas dans les exemples de données avec lesquels je travaille pour des raisons que j'ai déjà notées.

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
      ;
      
      

Voir une démonstration de travail de cette requête sur SQLFiddle

Résultats :

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

Il y a 2 RANGÉES - comme prévu. Une ligne pour le commentaire le plus récent et une autre ligne pour le commentaire suivant le plus récent. Il s'agit d'un comportement normal pour SQL et jusqu'à ce qu'un commentaire soit ajouté sous cette réponse, les lecteurs de la question supposeraient que ce comportement normal serait acceptable.

La question n'a pas de "résultat attendu" clairement articulé.

[Option 1 :Une ligne par requête Post, avec JUSQU'À 2 commentaires, colonnes ajoutées]

Dans un commentaire ci-dessous, il a été révélé que vous ne vouliez pas 2 lignes par publication et que ce serait une solution facile. Eh bien, c'est un peu facile MAIS il existe des options et les options sont dictées par l'utilisateur sous la forme d'exigences. SI la question avait un "résultat attendu", nous saurions alors quelle option choisir. Néanmoins, voici une 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
      ;

Voir la deuxième requête fonctionnant chez SQLFiddle

Résultats de la requête 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, concaténer les commentaires les plus récents dans une seule liste séparée par des virgules **

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
      

Voir cette troisième requête travaillant chez SQLFiddle

Résultats de la requête 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 |

** Résumé **

J'ai présenté 3 requêtes, chacune ne montre que les 2 commentaires les plus récents, mais chaque requête le fait d'une manière différente. La première requête (comportement par défaut) affichera 2 lignes pour chaque publication. L'option 2 ajoute une colonne mais supprime la deuxième ligne. L'option 3 concatène les 2 commentaires les plus récents.

Veuillez noter que :

  • La question manque de définitions de tableau couvrant toutes les colonnes
  • La question ne contient aucun exemple de données, ce qui rend plus difficile pour vous la compréhension des résultats présentés ici, mais également plus difficile pour nous de préparer des solutions
  • La question n'a pas non plus de "résultat attendu" définitif (le résultat souhaité), ce qui a rendu la réponse encore plus complexe

J'espère que les informations supplémentaires fournies seront utiles et que vous savez maintenant qu'il est normal que SQL présente les données sur plusieurs lignes. Si vous ne voulez pas ce comportement normal, veuillez préciser ce que vous voulez vraiment dans votre question.

Post-scriptum. Pour inclure encore une autre sous-requête pour "follows", vous pouvez utiliser une sous-requête similaire à celle que vous avez déjà. Il peut être ajouté avant ou après cette sous-requête. Vous pouvez également le voir en cours d'utilisation sur sqlfiddle ici

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

Bien que l'ajout d'une autre sous-requête puisse répondre à votre désir d'obtenir plus d'informations, la requête globale peut ralentir proportionnellement à la croissance de vos données. Une fois que vous avez choisi la fonctionnalité dont vous avez vraiment besoin, il peut être utile de déterminer les index dont vous avez besoin sur ces tables. (Je pense qu'il vous serait conseillé de demander cet avis séparément, et si vous le faites, assurez-vous d'inclure 1. le DDL complet de vos tables et 2. un plan d'explication de la requête.)