sql >> Database >  >> RDS >> Mysql

MYSQL-query - Ontvang de laatste opmerking met betrekking tot de post

Deze foutmelding

is meestal te wijten aan de definitie van uw kolommen en tabellen. Het betekent meestal dat er aan weerszijden van een gelijkteken verschillende sorteringen zijn. Wat u moet doen, is er een kiezen en die beslissing opnemen in uw vraag.

Het probleem met de sortering was hier in de CROSS JOIN van @prev_value waarvoor een expliciete sortering nodig was.

Ik heb ook de "row_number"-logica enigszins gewijzigd in een enkele cross-join en de if-logica naar het uiterste van de select-lijst verplaatst.

Hieronder worden enkele voorbeeldgegevens weergegeven. Er zijn voorbeeldgegevens nodig om query's mee te testen. Iedereen die uw vraag met werkende voorbeelden probeert te beantwoorden, heeft gegevens nodig. De reden dat ik het hier plaats, is tweeledig.

  1. zodat u elk resultaat begrijpt dat ik presenteer
  2. zodat u in de toekomst, wanneer u nog een SQL-gerelateerde vraag stelt, het belang van het verstrekken van gegevens begrijpt. Het is voor ons niet alleen handiger dat u dit doet. Als de vrager de voorbeeldgegevens verstrekt, zal de vrager het al begrijpen - het zal geen uitvinding zijn van een vreemde die een deel van hun tijd heeft besteed om te helpen.

Voorbeeldgegevens

Let op:sommige kolommen ontbreken in de tabellen, alleen de kolommen die in de tabeldetails zijn vermeld, zijn opgenomen.

Deze voorbeeldgegevens hebben 5 reacties op een enkele post (er worden geen likes geregistreerd)

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-standaardgedrag:2 rijen per postquery]

Dit was mijn eerste vraag, met enkele correcties. Ik heb de kolomvolgorde van de selectielijst gewijzigd, zodat u gemakkelijk enkele opmerkingengerelateerde gegevens kunt zien wanneer ik de resultaten presenteer. Bestudeer de resultaten die ze worden verstrekt, zodat u begrijpt wat de zoekopdracht zal doen. Kolommen voorafgegaan door # bestaan ​​niet in de voorbeeldgegevens waarmee ik werk om redenen die ik al heb opgemerkt.

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
      ;
      
      

Bekijk een werkende demonstratie van deze query op SQLFiddle

Resultaten :

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

Er zijn 2 RIJEN - zoals verwacht. Een rij voor de meest recente opmerking en een andere rij voor de volgende meest recente opmerking. Dit is normaal gedrag voor SQL en totdat een opmerking onder dit antwoord werd toegevoegd, zouden lezers van de vraag aannemen dat dit normale gedrag acceptabel zou zijn.

De vraag mist een duidelijk verwoord "verwacht resultaat".

[Optie 1:één rij per berichtquery, met TOT 2 opmerkingen, toegevoegde kolommen]

In een reactie hieronder werd onthuld dat je geen 2 rijen per bericht wilde en dit zou een gemakkelijke oplossing zijn. Nou, het is een beetje gemakkelijk MAAR er zijn opties en de opties worden bepaald door de gebruiker in de vorm van vereisten. ALS de vraag een "verwacht resultaat" had, dan zouden we weten welke optie we moeten kiezen. Desalniettemin is hier een optie

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
      ;

Zie de tweede query die werkt bij SQLFiddle

Resultaten van zoekopdracht 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 |

** Optie 2, voeg de meest recente opmerkingen samen tot één door komma's gescheiden lijst **

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
      

Bekijk deze derde zoekopdracht bij SQLFiddle

Resultaten van zoekopdracht 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 |

** Samenvatting **

Ik heb 3 query's gepresenteerd, elk toont alleen de 2 meest recente opmerkingen, maar elke query doet dat op een andere manier. De eerste zoekopdracht (standaardgedrag) toont 2 rijen voor elk bericht. Optie 2 voegt een kolom toe maar verwijdert de tweede rij. Optie 3 voegt de 2 meest recente opmerkingen samen.

Houd er rekening mee dat:

  • De vraag mist tabeldefinities die alle kolommen dekken
  • De vraag bevat geen voorbeeldgegevens, waardoor het moeilijker voor u is om de hier gepresenteerde resultaten te begrijpen, maar ook moeilijker voor ons om oplossingen voor te bereiden
  • De vraag mist ook een definitief "verwacht resultaat" (de gewenste output) en dit heeft geleid tot verdere complexiteit bij het beantwoorden

Ik hoop dat de extra verstrekte informatie van enig nut zal zijn, en dat u inmiddels ook weet dat het normaal is dat SQL gegevens als meerdere rijen presenteert. Als je dat normale gedrag niet wilt, wees dan specifiek over wat je echt wilt in je vraag.

Naschrift. Om nog een subquery voor "follows" op te nemen, kunt u een vergelijkbare subquery gebruiken als degene die u al heeft. Het kan voor of na die subquery worden toegevoegd. Je kunt het ook in gebruik zien op sqlfiddle hier

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

Hoewel het toevoegen van een andere subquery uw wens voor meer informatie kan oplossen, kan de algemene query langzamer worden in verhouding tot de groei van uw gegevens. Als je eenmaal hebt vastgesteld welke functionaliteit je echt nodig hebt, kan het de moeite waard zijn om te overwegen welke indexen je nodig hebt voor die tabellen. (Ik denk dat u geadviseerd wordt om dat advies apart te vragen, en als u dat doet, zorg er dan voor dat u 1. de volledige DDL van uw tabellen en 2. een uitlegplan van de query opneemt.)



  1. Oracle-cache uitschakelen voor prestatietests

  2. probleem ORA-00001:unieke beperking geschonden komt in INSERT/UPDATE

  3. Intel SSD, nu van de sh..err, beschaamde lijst

  4. Gratis webhosting met PHP-ondersteuning