PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Konvertieren von SELECT DISTINCT ON-Abfragen von Postgresql nach MySQL

Es gibt kein genaues Äquivalent zum Konvertieren einer Postgresql-Abfrage, die SELECT DISTINCT ON in MySQL verwendet.

Postgresql SELECT DISTINCT ON

In Postgresql löscht die folgende Abfrage alle Zeilen, in denen die Ausdrücke (col1, col2, col3) übereinstimmen, und es wird nur die "erste Spalte Spalte4, Spalte5" für jeden Satz übereinstimmender Zeilen behalten:

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

Wenn Ihre Tabelle also so aussieht:

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

Unsere Abfrage behält nur eine Zeile für (1,2,3) und eine Zeile für (3,3,3). Die resultierenden Zeilen sind dann:

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

Bitte beachten Sie, dass die "erste Zeile" jedes Satzes unvorhersehbar ist, unsere erste Zeile könnte auch (888, 999) sein, es sei denn, wir geben eine ORDER BY:

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

(Die DISTINCT on-Ausdrücke müssen mit den ORDER BY-Ausdrücken ganz links übereinstimmen, aber ORDER BY kann zusätzliche Ausdrücke enthalten).

MySQL-Erweiterung für GROUP BY

MySQL erweitert die Verwendung von GROUP BY, sodass wir nicht aggregierte Spalten auswählen können, die nicht in der GROUP BY-Klausel benannt sind. Immer wenn wir nicht aggregierte Spalten auswählen, kann der Server jeden Wert aus jeder Gruppe dieser Spalte auswählen, sodass die resultierenden Werte unbestimmt sind.

Also diese Postgresql-Abfrage:

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

kann als äquivalent zu dieser MySQL-Abfrage betrachtet werden:

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

Sowohl Postgresql als auch MySQL geben jeweils die „erste Zeile“ zurück (col1, col2, col3), und in beiden Fällen ist die zurückgegebene Zeile unvorhersehbar, da wir die Klausel nicht angegeben und sortiert haben.

Viele Leute wären sehr versucht, diese Postgresql-Abfrage mit einem ORDER BY:

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

mit diesem hier:

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

Die Idee hier ist, ein ORDER BY auf eine Unterabfrage anzuwenden, sodass MySQL, wenn es nach col1, col2, col3 gruppiert, den ersten gefundenen Wert für col4 und col5 behält. Die Idee ist gut, aber sie ist falsch! MySQL kann jeden Wert für col4 und col5 frei wählen, und wir wissen nicht, welche die ersten Werte sind, auf die wir stoßen, es hängt vom Optimierer ab. Also würde ich es folgendermaßen korrigieren:

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

aber das wird langsam komplizierter.

Fazit

Als allgemeine Regel gilt, dass es keinen genauen Weg gibt, eine Postgresql-Abfrage in eine MySQL-Abfrage zu konvertieren, aber es gibt viele Problemumgehungen, die resultierende Abfrage kann so einfach wie die ursprüngliche sein oder sehr kompliziert werden, aber es hängt davon ab die Abfrage selbst.