Mysql
 sql >> Database >  >> RDS >> Mysql

MYSQL - Ordina per ID nell'ordine DESC, raggruppa per X

Hai frainteso come funziona GROUP BY in SQL, a causa di una funzionalità di MySQL. In SQL standard ogni colonna non aggregata nell'istruzione SELECT DEVE essere nella clausola GROUP BY (c'è un'eccezione per le colonne i cui valori dipendono al 100% da una colonna già nella clausola GROUP BY, sebbene poche versioni di SQL supportino questa esenzione) .

MySQL non lo applica per impostazione predefinita, ma i valori delle righe utilizzati per quelle colonne non sono definiti. Mentre potresti ottenere quello che desideri, potresti anche non farlo. E anche se lo fai, c'è la possibilità che cambi in futuro.

L'ordinamento è normalmente indipendente da GROUP BY, anche se se non si specifica una clausola ORDER i risultati verranno ordinati in base a ciò che è stato richiesto per eseguire il GROUPing (cioè, se aiuta a ordinare le righe in un ordine per eseguire GROUP BY quindi MySQL non si preoccuperà di riordinare i record in seguito a meno che tu non lo dica espressamente con una clausola ORDER BY).

Quindi con i tuoi dati attuali, raggruppando per ads_post_id il valore dell'id che viene restituito potrebbe essere 22, 23, 24, 104, 250, 253 o 767. Quale MySQL sceglie di utilizzare non è definito.

Con la tua attuale correzione dei dati, questo è banale in quanto puoi semplicemente ottenere l'ID MAX:-

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

MAX restituirà 1 riga per ogni valore GROUPed.

Il problema normale è che le persone vogliono un'altra colonna per quella riga. Ad esempio, supponiamo che ciascuna delle righe nei tuoi dati di esempio avesse anche un indirizzo IP e che volevi quello che equivaleva all'ID più alto per 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 questo caso non puoi semplicemente usare MAX. Ad esempio se hai provato:-

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

Otterresti i seguenti dati restituiti

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

Se hai provato quanto segue nella maggior parte delle versioni di SQL, otterresti un errore. In MySQL con le impostazioni predefinite otterresti un risultato, ma quale indirizzo IP viene restituito non è definito (e in effetti casuale).

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

Le soluzioni a questo sono ottenere l'id massimo per ogni ads_post_id in una sottoquery e quindi unirlo alla tabella per ottenere il resto dei valori:-

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

Un'alternativa è (ab)utilizzare la funzione di aggregazione GROUP_CONCAT. GROUP_CONCAT riporterà tutti i valori concatenati insieme in 1 campo, ciascuno separato da un , (per impostazione predefinita). Puoi aggiungere una clausola ORDER BY per forzare l'ordine in cui sono concatenati. Puoi usare SUBSTRING_INDEX per restituire tutto fino alla prima virgola.

Questo può essere utile per dati semplici, ma diventa problematico con dati di testo o campi che possono essere al massimo NULL.

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