sql >> Databasteknik >  >> RDS >> PostgreSQL

Konvertera SELECT DISTINCT ON-frågor från Postgresql till MySQL

Det finns ingen exakt motsvarighet till att konvertera en Postgresql-fråga som använder SELECT DISTINCT ON till MySQL.

Postgresql VÄLJ DISTINCT PÅ

I Postgresql kommer följande fråga att eliminera alla rader där uttrycken (col1, col2, col3) matcha, och det kommer bara att behålla den "första kol4, kol5 raden" för varje uppsättning matchade rader:

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

Så om ditt bord är så här:

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

vår fråga kommer bara att behålla en rad för (1,2,3) och en rad för (3,3,3). De resulterande raderna blir då:

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

Observera att den "första raden" i varje uppsättning är oförutsägbar, vår första rad kan också vara (888, 999) om vi inte anger en BESTÄLLNING AV:

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

(DISTINCT på uttryck måste matcha ORDER BY-uttrycken längst till vänster, men ORDER BY kan innehålla ytterligare uttryck).

MySQL-tillägg till GROUP BY

MySQL utökar användningen av GROUP BY så att vi kan välja icke aggregerade kolumner som inte är namngivna i GROUP BY-satsen. Närhelst vi väljer icke aggregerade kolumner är servern fri att välja valfritt värde från varje grupp från den kolumnen, så de resulterande värdena kommer att vara obestämda.

Så denna Postgresql-fråga:

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

kan betraktas som likvärdig med denna MySQL-fråga:

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

både Postgresql och MySQL kommer att returnera "Första raden" för varje (col1, col2, col3), och i båda fallen är den returnerade raden oförutsägbar eftersom vi inte specificerade och sorterade efter klausul.

Många människor skulle vara mycket frestade att konvertera denna Postgresql-fråga med en BESTÄLLNING AV:

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

med den här:

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

Tanken här är att tillämpa en ORDER BY på en underfråga så att när MySQL grupperar efter col1, col2, col3 kommer det att behålla det första påträffade värdet för col4 och col5. Tanken är bra, men den är fel! MySQL är fri att välja vilket värde som helst för col4 och col5, och vi vet inte vilka som är de första värdena som påträffas, det beror på optimeraren. Så jag skulle rätta till det här:

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

men det här börjar bli mer komplicerat.

Slutsats

Som en allmän regel finns det inget exakt sätt att konvertera en Postgresql-fråga till en MySQL-fråga, men det finns många lösningar, den resulterande frågan kan vara lika enkel som den ursprungliga eller så kan den bli mycket komplicerad, men det beror på själva frågan.



  1. @GeneratedValue polymorf abstrakt superklass över MySQL

  2. Konvertera "datetimeoffset" till "datetime" i SQL Server (T-SQL-exempel)

  3. Skapa en skalär användardefinierad funktion i SQL Server

  4. Kan inte ansluta till localhost, men kan med datornamn i SQL Server 2008