sql >> Database >  >> RDS >> Mysql

MYSQL - Bestel op id in DESC-volgorde, groepeer op X

Je hebt verkeerd begrepen hoe GROUP BY werkt in SQL, vanwege een functie van MySQL. In standaard SQL MOET elke niet-geaggregeerde kolom in de SELECT-instructie in de GROUP BY-clausule staan ​​(er is een uitzondering voor kolommen waarvan de waarden 100% afhankelijk zijn van een kolom die al in de GROUP BY-clausule staat, hoewel weinig SQL-varianten deze uitzondering ondersteunen) .

MySQL dwingt dit niet standaard af, maar welke rijwaarden voor die kolommen worden gebruikt, is niet gedefinieerd. Hoewel je misschien degene krijgt die je wilt, misschien ook niet. En zelfs als je dat doet, is er een kans dat het in de toekomst zal veranderen.

De volgorde is normaal gesproken onafhankelijk van de GROUP BY, maar als u geen ORDER-clausule opgeeft, worden de resultaten gerangschikt op basis van wat nodig was om de GROUPing uit te voeren (dwz als het helpt om de rijen in één volgorde te ordenen om de GROUP BY, dan zal MySQL niet de moeite nemen om de records achteraf opnieuw te ordenen, tenzij u dit specifiek aangeeft met een ORDER BY-clausule).

Dus met uw huidige gegevens kan groepering op ads_post_id de waarde van id die wordt geretourneerd 22, 23, 24, 104, 250, 253 of 767 zijn. Welke MySQL ervoor kiest te gebruiken, is niet gedefinieerd.

Met uw huidige gegevenscorrectie is dit triviaal, omdat u gewoon de MAX-id kunt krijgen:-

SELECT ads_post_id, MAX(id) 
FROM fb_ads 
GROUP BY ads_post_id 
LIMIT 6

MAX retourneert 1 rij voor elke GROUPed-waarde.

Het normale probleem is dat mensen een andere kolom willen voor die rij. Stel bijvoorbeeld dat elk van de rijen in uw voorbeeldgegevens ook een IP-adres had en dat u het adres wilde dat overeenkwam met de hoogste id voor de ads_post_id:-

id   | ads_post_id         ip_address
---------------------------------------------------------------------------
22   | 983314845117571     192.168.0.0
23   | 983314845117571     192.168.0.5
24   | 983314845117571     192.168.0.7    
104  | 983314845117571     192.168.0.0
250  | 983314845117571     192.168.0.4
253  | 983314845117571     192.168.0.6
767  | 983314845117571     192.168.0.1     
---------------------------------------------------------------------------

In dit geval kunt u niet zomaar MAX gebruiken. Bijvoorbeeld als je het hebt geprobeerd:-

SELECT ads_post_id, MAX(id), MAX(ip_address) 
FROM fb_ads 
GROUP BY ads_post_id 
LIMIT 6

U krijgt de volgende gegevens terug

id   | ads_post_id         ip_address
---------------------------------------------------------------------------
767  | 983314845117571     192.168.0.7     
---------------------------------------------------------------------------

Als je het volgende in de meeste SQL-varianten zou proberen, zou je een foutmelding krijgen. In MySQL met de standaardinstellingen zou je een resultaat krijgen, maar welk IP-adres wordt geretourneerd is niet gedefinieerd (en in feite willekeurig).

SELECT ads_post_id, MAX(id), ip_address 
FROM fb_ads 
GROUP BY ads_post_id 
LIMIT 6

De oplossingen hiervoor zijn ofwel om de maximale id voor elke ads_post_id in een subquery te krijgen en die vervolgens weer in de tabel te plaatsen om de rest van de waarden te krijgen:-

SELECT a.ads_post_id,
        a.id,
        a.ip_address
FROM fb_ads a
INNER JOIN
(
    SELECT ads_post_id, MAX(id) AS max_id 
    FROM fb_ads 
    GROUP BY ads_post_id 
) sub0
ON a.ads_post_id = sub0.ads_post_id
AND a.id = sub0.max_id

Een alternatief is om (ab)gebruik te maken van de GROUP_CONCAT aggregatiefunctie. GROUP_CONCAT brengt alle aaneengeschakelde waarden terug in 1 veld, elk gescheiden door een , (standaard). U kunt een ORDER BY-clausule toevoegen om de volgorde waarin ze worden samengevoegd te forceren. U kunt SUBSTRING_INDEX gebruiken om alles terug te brengen tot de eerste komma.

Dit kan handig zijn voor eenvoudige gegevens, maar wordt problematisch bij tekstgegevens of velden die maximaal NULL zijn.

SELECT a.ads_post_id,
        SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY id DESC), ',', 1),
        SUBSTRING_INDEX(GROUP_CONCAT(ip_address ORDER BY id DESC), ',', 1)
FROM fb_ads 
GROUP BY ads_post_id 


  1. Wat is MariaDB ColumnStore?

  2. Verschil tussen mysql_fetch_array en mysql_fetch_row?

  3. MySQL-werkbank

  4. MySQL Bereken leeftijd per jaar, maand en dag