PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Conversione di query SELECT DISTINCT ON da Postgresql a MySQL

Non esiste un equivalente esatto per convertire una query Postgresql che utilizza SELECT DISTINCT ON in MySQL.

Postgresql SELEZIONA DISTINTO ATTIVO

In Postgresql, la query seguente eliminerà tutte le righe in cui le espressioni (col1, col2, col3) corrispondenza e manterrà solo la "prima riga col4, col5" per ogni set di righe abbinate:

SELECT DISTINCT ON (col1, col2, col3) col4, col5
FROM tablename

Quindi se la tua tabella è così:

col1 | col2 | col3 | col4 | col5
--------------------------------
1    | 2    | 3    | 777  | 888
1    | 2    | 3    | 888  | 999
3    | 3    | 3    | 555  | 555

la nostra query manterrà solo una riga per (1,2,3) e una riga per (3,3,3). Le righe risultanti saranno quindi:

col4 | col5
-----------
777  | 888
555  | 555

si prega di notare che la "prima riga" di ogni set è imprevedibile, anche la nostra prima riga potrebbe essere (888, 999) a meno che non specifichiamo un ORDINE PER:

SELECT DISTINCT ON (col1, col2, col3) col4, col5
FROM tablename
ORDER BY col1, col2, col3, col4

(il DISTINCT sulle espressioni deve corrispondere alle espressioni ORDER BY più a sinistra, ma ORDER BY può contenere espressioni aggiuntive).

Estensione MySQL per GROUP BY

MySQL estende l'uso di GROUP BY in modo da poter selezionare colonne non aggregate non nominate nella clausola GROUP BY. Ogni volta che selezioniamo colonne non aggregate, il server è libero di scegliere qualsiasi valore da ciascun gruppo di quella colonna, quindi i valori risultanti saranno indeterminati.

Quindi questa query Postgresql:

SELECT DISTINCT ON (col1, col2, col3) col4, col5
FROM tablename

può essere considerato equivalente a questa query MySQL:

SELECT col4, col5
FROM tablename
GROUP BY col1, col2, col3

sia Postgresql che MySQL restituiranno la "Prima riga" per ciascuno (col1, col2, col3) e in entrambi i casi la riga restituita è imprevedibile perché non abbiamo specificato e ordinato per clausola.

Molte persone sarebbero molto tentate di convertire questa query Postgresql con un ORDER BY:

SELECT DISTINCT ON (col1, col2, col3) col4, col5
FROM tablename
ORDER BY col1, col2, col3, col4

con questo:

SELECT col4, col5
FROM (
  SELECT col1, col2, col3, col4, col5
  FROM tablename
  ORDER BY col1, col2, col3, col4
) s
GROUP BY col1, col2, col3

l'idea qui è di applicare un ORDER BY a una sottoquery in modo che quando MySQL raggruppa per col1, col2, col3 manterrà il primo valore incontrato per col4 e col5. L'idea è buona, ma è sbagliata! MySQL è libero di scegliere qualsiasi valore per col4 e col5 e non sappiamo quali siano i primi valori incontrati, dipende dall'ottimizzatore. Quindi lo correggerei in questo modo:

SELECT t1.col4, t1.col5
FROM tablename t1 INNER JOIN (SELECT col1, col2, col3, MIN(col4) as m_col4
                              FROM tablename
                              GROUP BY col1, col2, col3) s
     ON t1.col1=s.col1
        AND t1.col2=s.col2
        AND t1.col3=s.col3
        AND t1.col4=s.m_col4
GROUP BY
  t1.col1, t1.col2, t1.col3, t1.col4

ma questo inizia a diventare più complicato.

Conclusione

Come regola generale, non esiste un modo esatto per convertire una query Postgresql in una query MySQL, ma ci sono molte soluzioni alternative, la query risultante potrebbe essere semplice come quella originale o potrebbe diventare molto complicata, ma dipende da la query stessa.