web-dev-qa-db-ja.com

SQL仕様ではEXISTS()にGROUP BYが必要ですか?

マイクロソフトでは現在、この構文を許可しています。

SELECT *
FROM ( VALUES (1) ) AS g(x)
WHERE EXISTS (
  SELECT *
  FROM ( VALUES (1),(1) )
    AS t(x)
  WHERE g.x = t.x
  HAVING count(*) > 1
);

EXISTS句にGROUP BYがないことに注意してください。これは有効なANSI SQLです。それとも単に実装の詳細を公開するだけなのでしょうか。

参考までに、これと同じ構文はPostgreSQLでは許可されていません。

エラー:列 "t.x"はGROUP BY句に出現するか、集計関数で使用する必要があります

しかし、この構文は許可されています。

SELECT *
FROM ( VALUES (1) ) AS g(x)
WHERE EXISTS (
  SELECT 1  -- This changed from the first query
  FROM ( VALUES (1),(1) )
    AS t(x)
  WHERE g.x = t.x
  HAVING count(*) > 1
);

そして、この構文は許可されています。

SELECT *
FROM ( VALUES (1) ) AS g(x)
WHERE EXISTS (
  SELECT *
  FROM ( VALUES (1),(1) )
    AS t(x)
  WHERE g.x = t.x
  GROUP BY t.x  -- This changed from the first query
  HAVING count(*) > 1
);

質問は チャットでの@ErikEとの会話から発生します

11
Evan Carroll

SQL 2011仕様で見つけました...

<select list>“ *”が単に<table subquery>に含まれる<exists predicate>に単純に含まれている場合、<select list><value expression>と同等です。任意の<literal>

これは、このコンテキストでの*が任意のリテラルと同等ではないことを確認しますそれは実際にPostgreSQLが仕様に違反していることを示しています。

これは別の問題であることを覚えておいてください

SELECT *
FROM ( VALUES (1),(2),(3) ) AS t(x)
HAVING count(*) > 1

どちらのデータベースが拒否するか。

PostgreSQL、

エラー:列 "t.x"はGROUP BY句に出現するか、集計関数で使用する必要があります

SQLサーバー、

列 't.x'は、集約関数にもGROUP BY句にも含まれていないため、選択リストでは無効です。

このバグがPostgreSQLで持続する理由

これをトラブルシューティングしてくれたirc.freenode.net/#PostgreSQLのRhodiumToadに感謝します。彼はまた、この状況を解決することの難しさを指摘しています

20:33 <RhodiumToad> 1つの問題は、pgで存在できることです(select func()from ... where func()は0行を返す可能性があるSRFです)

SRFは セットを返す関数です

PostgreSQLでは、たとえばSRFを使用して1〜10のシリーズを生成できます(generate_seriesはコアにあります)

SELECT * FROM generate_series(1,10); 

そして、同様にここに置くことができます。

SELECT generate_series(1,10);

それらの2つを一緒に使用すると、クロス結合(デカルト積)が得られます

SELECT generate_series(1,10), generate_series(1,2);

しかし、これらのいずれかが0行を返す場合、何も得られません。実質的にこれと同じです

SELECT * FROM ( VALUES (1) ) AS t(x)
CROSS JOIN ( SELECT 1 LIMIT 0 ) AS g;

そして、それはこれを完全に最適化することの問題です。 0行を返すEXISTステートメント内の選択リストにSRFを含めることができ、EXISTSを強制的にfalseに評価します。

11
Evan Carroll