Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Consulta MYSQL - Obtenha o comentário mais recente relacionado à postagem


Esta mensagem de erro

é normalmente devido à definição de suas colunas e tabelas. Geralmente significa que em ambos os lados de um sinal de igual existem diferentes agrupamentos. O que você precisa fazer é escolher um e incluir essa decisão em sua consulta.

O problema de agrupamento aqui estava no CROSS JOIN de @prev_value que precisava de um agrupamento explícito para ser usado.

Também alterei ligeiramente a lógica "row_number" para uma única junção cruzada e movi a lógica if para os extremos da lista de seleção.

Alguns dados de exemplo são exibidos abaixo. Os dados de amostra são necessários para testar as consultas. Qualquer pessoa que tente responder à sua pergunta com exemplos práticos precisará de dados. A razão pela qual estou incluindo aqui é dupla.
  1. para que você entenda qualquer resultado que eu apresentar
  2. para que, no futuro, quando você fizer outra pergunta relacionada ao SQL, entenda a importância de fornecer dados. Não é apenas mais conveniente para nós que você faça isso. Se o solicitante fornecer os dados de amostra, ele já o entenderá - não será uma invenção de algum estranho que dedicou parte de seu tempo para ajudar.

Dados de amostra

Observe que algumas colunas estão faltando nas tabelas, apenas as colunas especificadas nos detalhes da tabela foram incluídas.

Esses dados de amostra têm 5 comentários em uma única postagem (nenhuma curtida é registrada)
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 padrão SQL:2 linhas por consulta de postagem]

Esta foi a minha consulta inicial, com algumas correções. Mudei a ordem das colunas da lista de seleção para que você veja facilmente alguns dados relacionados a comentários quando eu apresentar os resultados. Por favor, estude os resultados que são fornecidos para que você possa entender o que a consulta fará. Colunas precedidas por # não existem nos dados de amostra com os quais estou trabalhando por motivos que já observei.
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
      ;
      
      

Veja uma demonstração funcional desta consulta no SQLFiddle

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

Existem 2 LINHAS - como esperado. Uma linha para o comentário mais recente e outras linhas para o próximo comentário mais recente. Este é um comportamento normal para SQL e até que um comentário fosse adicionado nesta resposta, os leitores da pergunta assumiriam que esse comportamento normal seria aceitável.

A questão carece de um "resultado esperado" claramente articulado.

[Opção 1:uma linha por consulta de postagem, com até 2 comentários, colunas adicionadas]

Em um comentário abaixo, foi revelado que você não queria 2 linhas por postagem e isso seria uma solução fácil. Bem, é meio fácil, MAS existem opções e as opções são ditadas pelo usuário na forma de requisitos. SE a pergunta tivesse um "resultado esperado", saberíamos qual opção escolher. No entanto, aqui está uma opção
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
      ;

Veja a segunda consulta trabalhando no SQLFiddle

Resultados da consulta 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 |

** Opção 2, concatenar os comentários mais recentes em uma única lista separada por vírgulas **
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
      

Veja esta terceira consulta trabalhando no SQLFiddle

Resultados da consulta 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 |

** Resumo **

Eu apresentei 3 consultas, cada uma mostra apenas os 2 comentários mais recentes, mas cada consulta faz isso de uma forma diferente. A primeira consulta (comportamento padrão) exibirá 2 linhas para cada postagem. A opção 2 adiciona uma coluna, mas remove a segunda linha. A opção 3 concatena os 2 comentários mais recentes.

Observe que:
  • A questão não tem definições de tabela cobrindo todas as colunas
  • A questão não tem dados de amostra, o que dificulta a compreensão dos resultados apresentados aqui, mas também dificulta a preparação de soluções
  • A pergunta também carece de um "resultado esperado" definitivo (a saída desejada) e isso levou a uma maior complexidade na resposta

Espero que as informações adicionais fornecidas sejam de alguma utilidade e que agora você também saiba que é normal que o SQL apresente dados como várias linhas. Se você não deseja esse comportamento normal, seja específico sobre o que você realmente deseja em sua pergunta.

Pós-escrito. Para incluir outra subconsulta para "follows", você pode usar uma subconsulta semelhante à que você já possui. Pode ser adicionado antes ou depois dessa subconsulta. Você também pode vê-lo em uso em sqlfiddle aqui
LEFT JOIN (
          SELECT
                COUNT(*) FollowCNT
              , IdOtherUser
          FROM Activity
          WHERE type = 'Follow'
          GROUP BY
                IdOtherUser
          ) F ON USERS.id = F.IdOtherUser

Embora a adição de outra subconsulta possa resolver seu desejo de obter mais informações, a consulta geral pode ficar mais lenta em proporção ao crescimento de seus dados. Depois de definir a funcionalidade que você realmente precisa, pode valer a pena considerar quais índices você precisa nessas tabelas. (Acredito que você seria aconselhado a pedir esse conselho separadamente e, se o fizer, certifique-se de incluir 1. o DDL completo de suas tabelas e 2. um plano de explicação da consulta.)