次のようなクエリがあるとします。
SELECT g, v
FROM t
GROUP BY g;
この場合、の可能な値ごとにg
、mysqlはの対応する値の1つを選択しますv
。
ただし、どちらを選択するかは、状況によって異なります。
v
gの各グループについて、レコードがテーブルに挿入された順序で、の最初の値が保持されていることをどこかで読みましたt
。
テーブル内のレコードは、要素の順序が重要ではないセットとして扱われる必要があるため、これは非常に醜いです。これはとても「mysqlっぽい」です...
保持する値を決定する場合は、次のようv
に副選択を適用する必要があります。t
SELECT g, v
FROM (
SELECT *
FROM t
ORDER BY g, v DESC
) q
GROUP BY g;
このようにして、サブクエリのレコードが外部クエリによって処理される順序を定義します。したがってv
、の個々の値に対してどの値が選択されるかを信頼できますg
。
ただし、WHERE条件が必要な場合は、十分に注意してください。WHERE条件をサブクエリに追加すると、動作が維持され、常に期待する値が返されます。
SELECT g, v
FROM (
SELECT *
FROM t
WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9'
ORDER BY g, v DESC
) q
GROUP BY g;
これはあなたが期待することであり、副選択はテーブルをフィルタリングして順序付けます。g
指定された値を持つレコードを保持し、外部クエリはそれg
との最初の値を返しますv
。
ただし、同じWHERE条件を外部クエリに追加すると、非決定論的な結果が得られます。
SELECT g, v
FROM (
SELECT *
FROM t
-- WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9'
ORDER BY g, v DESC
) q
WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9'
GROUP BY g;
驚いたことに、同じクエリを何度も実行すると、異なる値が表示されるv
場合があります。これは奇妙なことです。予想される動作は、サブクエリから適切な順序ですべてのレコードを取得し、外部クエリでそれらをフィルタリングしてから、前の例で選択したものと同じものを選択することです。しかし、そうではありません。
v
一見ランダムに値を選択します。v
同じクエリが、より多く(〜20)回実行した場合に異なる値を返しましたが、分布は均一ではありませんでした。
外部WHEREを追加する代わりに、次のようにHAVING条件を指定する場合:
SELECT g, v
FROM (
SELECT *
FROM t1
-- WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9'
ORDER BY g, v DESC
) q
-- WHERE g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9'
GROUP BY g
HAVING g = '737a8783-110c-447e-b4c2-1cbb7c6b72c9';
その後、再び一貫した動作が得られます。
結論:この手法にまったく依存しないことをお勧めします。本当に必要な場合は、外部クエリでWHERE条件を回避してください。可能であれば内部クエリで使用するか、外部クエリでHAVING句を使用します。
私はこのデータでそれをテストしました:
CREATE TABLE t1 (
v INT,
g VARCHAR(36)
);
INSERT INTO t1 VALUES (1, '737a8783-110c-447e-b4c2-1cbb7c6b72c9');
INSERT INTO t1 VALUES (2, '737a8783-110c-447e-b4c2-1cbb7c6b72c9');
mysql5.6.41で。
新しいバージョンで修正された/修正されたバグかもしれません。新しいバージョンの経験がある場合は、フィードバックをお寄せください。