Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Zapytanie MYSQL - Pobierz najnowszy komentarz związany z postem

Ten komunikat o błędzie

wynika to zazwyczaj z definicji Twoich kolumn i tabel. Zwykle oznacza to, że po obu stronach znaku równości znajdują się różne zestawienia. Musisz tylko wybrać jedną i uwzględnić tę decyzję w zapytaniu.

Problem z sortowaniem dotyczył tutaj CROSS JOIN @prev_value, które wymagało użycia jawnego sortowania.

Zmieniłem też nieco logikę "row_number" na pojedyncze sprzężenie krzyżowe i przeniosłem logikę if na skrajne granice listy wyboru.

Niektóre przykładowe dane są wyświetlane poniżej. Do testowania zapytań potrzebne są przykładowe dane. Każdy, kto spróbuje odpowiedzieć na Twoje pytanie za pomocą działających przykładów, będzie potrzebował danych. Powód, dla którego to tutaj zamieszczam, jest dwojaki.

  1. abyś zrozumiał każdy wynik, który przedstawiam
  2. aby w przyszłości, gdy zadasz kolejne pytanie związane z SQL, zrozumiałeś, jak ważne jest dostarczanie danych. To nie tylko dla nas wygodniejsze, jeśli to zrobisz. Jeśli pytający dostarczy przykładowe dane, to już je zrozumie – nie będzie to wymysł jakiejś nieznajomej, która poświęciła trochę czasu na pomoc.

Przykładowe dane

Należy pamiętać, że w tabelach brakuje niektórych kolumn, uwzględniono tylko kolumny określone w szczegółach tabeli.

Te przykładowe dane zawierają 5 komentarzy do jednego posta (nie są rejestrowane polubienia)

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

[Standardowe zachowanie SQL:2 wiersze na zapytanie Post]

To było moje początkowe zapytanie, z pewnymi poprawkami. Zmieniłem kolejność kolumn na liście wyboru, aby łatwo zobaczyć niektóre dane związane z komentarzami, gdy przedstawię wyniki. Prosimy o zapoznanie się z podanymi wynikami, aby móc zrozumieć, co spowoduje zapytanie. Kolumny poprzedzone # nie istnieją w przykładowych danych, z którymi pracuję z powodów, o których już wspomniałem.

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
      ;
      
      

Zobacz działającą demonstrację tego zapytania w SQLFiddle

Wyniki :

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

Istnieją 2 RZĘDY - zgodnie z oczekiwaniami. Jeden wiersz na najnowszy komentarz i kolejne wiersze na kolejny najnowszy komentarz. Jest to normalne zachowanie SQL i dopóki nie zostanie dodany komentarz pod tą odpowiedzią, czytelnicy pytania zakładają, że to normalne zachowanie jest dopuszczalne.

W pytaniu brakuje jasno wyartykułowanego „oczekiwanego wyniku”.

[Opcja 1:jeden wiersz na zapytanie Post, DO 2 komentarzy, dodane kolumny]

W komentarzu poniżej ujawniono, że nie chcesz 2 wierszy na post i byłoby to łatwe rozwiązanie. Cóż, to trochę proste, ALE są opcje i opcje są dyktowane przez użytkownika w postaci wymagań. JEŚLI pytanie miałoby „oczekiwany wynik”, to wiedzielibyśmy, którą opcję wybrać. Niemniej jednak jest jedna opcja

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
      ;

Zobacz drugie zapytanie działające w SQLFiddle

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

** Opcja 2, połącz najnowsze komentarze w jedną listę oddzieloną przecinkami **

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
      

Zobacz trzecie zapytanie działające w SQLFiddle

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

** Podsumowanie **

Przedstawiłem 3 zapytania, każde pokazuje tylko 2 najnowsze komentarze, ale każde zapytanie robi to w inny sposób. Pierwsze zapytanie (zachowanie domyślne) wyświetli 2 wiersze na każdy post. Opcja 2 dodaje kolumnę, ale usuwa drugi wiersz. Opcja 3 łączy 2 najnowsze komentarze.

Należy pamiętać, że:

  • W pytaniu brakuje definicji tabel obejmujących wszystkie kolumny
  • W pytaniu brakuje jakichkolwiek przykładowych danych, co utrudnia zrozumienie prezentowanych tu wyników, ale także utrudnia nam przygotowanie rozwiązań
  • Pytaniu brakuje również ostatecznego „oczekiwanego wyniku” (pożądany wynik), co prowadzi do dalszej złożoności odpowiedzi

Mam nadzieję, że te dodatkowe informacje okażą się przydatne i że już wiesz, że SQL przedstawianie danych w wielu wierszach jest normalne. Jeśli nie chcesz tego normalnego zachowania, określ dokładnie, czego naprawdę chcesz w swoim pytaniu.

Postscriptum. Aby dołączyć jeszcze jedno podzapytanie dla „obserwacji”, możesz użyć podzapytania podobnego do tego, które już masz. Może być dodany przed lub po tym podzapytaniu. Możesz go również zobaczyć w użyciu w sqlfiddle tutaj

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

Chociaż dodanie kolejnego podzapytania może rozwiązać Twoje pragnienie uzyskania większej ilości informacji, ogólne zapytanie może być wolniejsze proporcjonalnie do wzrostu danych. Po ustaleniu funkcjonalności, której naprawdę potrzebujesz, warto zastanowić się, jakich indeksów potrzebujesz w tych tabelach. (Uważam, że zaleca się, aby poprosić o tę poradę osobno, a jeśli to zrobisz, upewnij się, że zawierasz 1. pełne DDL swoich tabel i 2. wyjaśnij plan zapytania.)



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MYSQL różni się w danych wyjściowych od skryptu

  2. Jak mogę wyszukiwać w tabeli wartości oddzielonych przecinkami?

  3. Odzyskaj miejsce na dysku po upuszczeniu bazy danych w mysql

  4. PHP- wstawianie danych binarnych w mysql za pomocą przygotowanych instrukcji

  5. użyj wartości kolumny jako nazwy kolumny mysql