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


11

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

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
);

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

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

エラー:列 "tx"は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

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、

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

SQLサーバー、

列 'tx'は、集約関数にも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に評価します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.