sql >> Database >  >> RDS >> PostgreSQL

SELECT DISTINCT ON-query's converteren van Postgresql naar MySQL

Er is geen exact equivalent voor het converteren van een Postgresql-query die gebruikmaakt van SELECT DISTINCT ON naar MySQL.

Postgresql SELECTEER DISTINCT ON

In Postgresql elimineert de volgende query alle rijen waarin de uitdrukkingen (col1, col2, col3) overeenkomen, en het behoudt alleen de "eerste col4, col5 rij" voor elke set overeenkomende rijen:

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

Dus als je tafel er zo uitziet:

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

onze query houdt slechts één rij voor (1,2,3) en één rij voor (3,3,3). De resulterende rijen zijn dan:

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

houd er rekening mee dat de "eerste rij" van elke set onvoorspelbaar is, onze eerste rij kan dat ook zijn (888, 999), tenzij we een ORDER BY specificeren:

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

(De DISTINCT op expressies moet overeenkomen met de meest linkse ORDER BY-expressies, maar de ORDER BY kan extra expressies bevatten).

MySQL-extensie voor GROUP BY

MySQL breidt het gebruik van GROUP BY uit, zodat we niet-geaggregeerde kolommen kunnen selecteren die niet in de GROUP BY-clausule worden genoemd. Telkens wanneer we niet-geaggregeerde kolommen selecteren, is de server vrij om elke waarde uit elke groep uit die kolom te kiezen, dus de resulterende waarden zullen onbepaald zijn.

Dus deze Postgresql-query:

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

kan worden beschouwd als gelijkwaardig aan deze MySQL-query:

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

zowel Postgresql als MySQL retourneert de "Eerste rij" voor elk (col1, col2, col3), en in beide gevallen is de geretourneerde rij onvoorspelbaar omdat we niet hebben gespecificeerd en geordend op clausule.

Veel mensen zouden in de verleiding komen om deze Postgresql-query om te zetten met een ORDER BY:

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

met deze:

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

het idee hier is om een ​​ORDER BY toe te passen op een subquery, zodat wanneer MySQL groepeert op col1, col2, col3, het de eerste gevonden waarde voor col4 en col5 behoudt. Het idee is goed, maar het is verkeerd! MySQL is vrij om elke waarde voor col4 en col5 te kiezen, en we weten niet welke de eerste waarden zijn die we tegenkomen, het hangt af van de optimizer. Dus ik zou het als volgt corrigeren:

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

maar dit begint ingewikkelder te worden.

Conclusie

Als algemene regel geldt dat er geen exacte manier is om een ​​Postgresql-query om te zetten in een MySQL-query, maar er zijn veel oplossingen:de resulterende query kan net zo eenvoudig zijn als de oorspronkelijke of het kan erg ingewikkeld worden, maar het hangt af van de vraag zelf.



  1. SQL-alias uitgelegd

  2. Transparante gegevensversleuteling en altijd versleuteld

  3. Geef een lijst met gehele getallen door van C# naar de opgeslagen procedure van Oracle

  4. Leer de MySQL-database gebruiken