PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Conversion des requêtes SELECT DISTINCT ON de Postgresql vers MySQL

Il n'y a pas d'équivalent exact pour convertir une requête Postgresql qui utilise SELECT DISTINCT ON en MySQL.

Postgresql SELECT DISTINCT ON

Dans Postgresql, la requête suivante éliminera toutes les lignes où les expressions (col1, col2, col3) match, et il ne conservera que la "première ligne col4, col5" pour chaque ensemble de lignes correspondantes :

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

Donc, si votre table ressemble à ceci :

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

notre requête ne conservera qu'une ligne pour (1,2,3) et une ligne pour (3,3,3). Les lignes résultantes seront alors :

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

veuillez noter que la "première ligne" de chaque ensemble est imprévisible, notre première ligne peut également être (888, 999) à moins que nous ne spécifions un ORDER BY :

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

(les expressions DISTINCT on doivent correspondre aux expressions ORDER BY les plus à gauche, mais ORDER BY peut contenir des expressions supplémentaires).

Extension MySQL pour GROUP BY

MySQL étend l'utilisation de GROUP BY afin que nous puissions sélectionner des colonnes non agrégées non nommées dans la clause GROUP BY. Chaque fois que nous sélectionnons des colonnes non agrégées, le serveur est libre de choisir n'importe quelle valeur de chaque groupe de cette colonne, de sorte que les valeurs résultantes seront indéterminées.

Donc cette requête Postgresql :

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

peut être considéré comme équivalent à cette requête MySQL :

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

Postgresql et MySQL renverront tous deux la "première ligne" pour chacun (col1, col2, col3), et dans les deux cas, la ligne renvoyée est imprévisible car nous n'avons pas spécifié et ordonné par clause.

Beaucoup de gens seraient très tentés de convertir cette requête Postgresql avec un ORDER BY :

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

avec celui-ci :

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'idée ici est d'appliquer un ORDER BY à une sous-requête afin que lorsque MySQL groupe par col1, col2, col3, il conserve la première valeur rencontrée pour col4 et col5. L'idée est bonne, mais elle est fausse ! MySQL est libre de choisir n'importe quelle valeur pour col4 et col5, et nous ne savons pas quelles sont les premières valeurs rencontrées, cela dépend de l'optimiseur. Je corrigerais donc ceci :

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

mais cela commence à se compliquer.

Conclusion

En règle générale, il n'y a pas de moyen exact de convertir une requête Postgresql en requête MySQL, mais il existe de nombreuses solutions de contournement, la requête résultante peut être aussi simple que la requête d'origine ou elle peut devenir très compliquée, mais cela dépend de la requête elle-même.