web-dev-qa-db-ja.com

SELECT DISTINCT ONクエリをPostgresqlからMySQLに変換する

私はPostgreSQLを使用しており、現在MySQLに移行しています。

私のクエリではPostgreSQLSELECT DISTINCT ON (col1, col2, col3)を使用していますが、このステートメントに対応するものがMySQLにあるかどうか疑問に思っていました。

28

SELECT DISTINCT ONを使用するPostgresqlクエリをMySQLに変換するための正確な同等物はありません。

Postgresql SELECT DISTINCT ON

Postgresqlでは、次のクエリは式(col1, col2, col3)が一致するすべての行を削除し、一致する行のセットごとに「最初のcol4、col5行」のみを保持します。

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

したがって、テーブルが次のような場合:

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

このクエリでは、(1,2,3)の1行と(3,3,3)の1行のみが保持されます。結果の行は次のようになります。

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

各セットの「最初の行」は予測できないことに注意してください。ORDERBYを指定しない限り、最初の行も(888、999)になる可能性があります。

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

(式のDISTINCTは左端のORDER BY式と一致する必要がありますが、ORDER BYには追加の式を含めることができます)。

MySQL SQLのGROUP BYへの拡張

MySQLは GROUP BY の使用を拡張して、GROUP BY句で指定されていない非集約列を選択できるようにします。集計されていない列を選択するときはいつでも、サーバーはその列から各グループから任意の値を自由に選択できるため、結果の値は不確定になります。

したがって、このPostgresqlクエリ:

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

このMySQLクエリと同等と見なすことができます。

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

postgresqlとMySQLはそれぞれ(col1、col2、col3)の「最初の行」を返します。句を指定していないため、どちらの場合も返される行は予測できません。

多くの人は、ORDER BYを使用してこのPostgresqlクエリを変換することに非常に魅力的です。

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

これで:

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

ここでの考え方は、ORDER BYをサブクエリに適用して、MySQLがcol1、col2、col3でグループ化するときに、最初に検出されたcol4およびcol5の値を保持することです。 アイデアは良いですが、それは間違っています!MySQLは、col4とcol5の任意の値を自由に選択でき、どちらが最初の値かはわかりません。遭遇した場合、それはオプティマイザに依存します。だから私はこれを修正します:

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

しかし、これはより複雑になり始めています。

結論

一般的なルールとして、PostgresqlクエリをMySQLクエリに変換する正確な方法はありませんが、多くの回避策があります。結果のクエリは元のクエリと同じくらい単純になるか、非常に複雑になる可能性がありますが、クエリ自体。

37
fthiella

サブクエリを使用して順序を決定し、外部クエリを使用してそれらをグループ化します。

@a_horse_with_no_nameが指摘するように、これはMySQLが部分的なgroup by、他のDBMSとは異なり。

例えば:

CREATE TABLE customer_order
    (`customer` varchar(5), `item` varchar(6), `date` datetime)
;

INSERT INTO customer_order
    (`customer`, `item`, `date`)
VALUES
    ('alice', 'widget', '2000-01-05 00:00:00'),
    ('bob', 'widget', '2000-01-02 00:00:00'),
    ('alice', 'widget', '2000-01-01 00:00:00'),
    ('alice', 'wodget', '2000-01-06 00:00:00')
;

各顧客の最初の注文のクエリ:

select *
from
  (select customer, item, date
  from customer_order
  order by date) c
group by customer

結果:

| CUSTOMER |   ITEM |                           DATE |
|----------|--------|--------------------------------|
|    alice | widget | January, 01 2000 00:00:00+0000 |
|      bob | widget | January, 02 2000 00:00:00+0000 |

http://sqlfiddle.com/#!2/6cbbe/1

0
Alex Wittig