web-dev-qa-db-ja.com

WHERE col1、col2 IN(...)[複合主キーを使用したSQLサブクエリ]

複合主キー(a,b)を持つテーブルfooが与えられた場合、次のようなクエリを記述するための正当な構文があります。

SELECT ... FROM foo WHERE a,b IN (SELECT ...many tuples of a/b values...);
UPDATE foo SET ... WHERE a,b IN (SELECT ...many tuples of a/b values...);

これが不可能で、スキーマを変更できなかった場合、上記と同等の方法を実行できますか?

これらのエイリアスでの検索ヒットのために、「複合主キー」、「副選択」、「副選択」、および「副照会」という用語をここに入れます。

編集:私は、標準SQLの回答だけでなく、PostgreSQLとSQLite 3で動作する回答にも興味があります。

35
Phrogz
sqlite> create table foo (a,b,c);
sqlite> create table bar (x,y);
sqlite> select * from foo where exists (select 1 from bar where foo.a = bar.x and foo.b = bar.y);

select 1 from barselect ... many tuples of a/b values ...に置き換えます。

または、select ... many tuples of a/b values ...の一時テーブルを作成し、barの代わりに使用します。

26
Doug Currie

構文は標準SQLに非常に近いです!

以下は有効なFULL SQL-92です( Mimer SQL-92 Validator で確認済み)

_SELECT * 
  FROM foo 
  WHERE (a, b) IN (
                   SELECT a, b 
                      FROM bar
                  );
_

もちろん、すべてのSQL製品が完全なSQL-92(恥ずかしい!)をサポートしているわけではありません。MicrosoftSQL Serverでサポートされているこの構文を見たい人は、投票できます here

(たとえば、Microsoft SQL ServerとOracleによって)より広くサポートされているSQL-92コンストラクトは、INTERSECTです。

_SELECT a, b
  FROM Foo
INTERSECT
SELECT a, b
  FROM Bar;
_

これらの他の提案のいくつかとは異なり、これらのコンストラクトはNULL値を適切に処理することに注意してください。 EXISTS (<equality predicates>)、連結値などを使用するもの.

19
onedaywhen

あなたは1つの非常に小さな間違いをしました。 a、bを括弧で囲む必要があります。

SELECT ... FROM foo WHERE (a,b) IN (SELECT f,d FROM ...);

動作します!

9
Ostin

提案されたIN構文は有効なSQLではありません。 EXISTSを使用したソリューションは、合理的に準拠したすべてのSQL RDBMSで機能するはずです。

 UPDATE foo SET x = y WHERE EXISTS
    (SELECT * FROM bar WHERE bar.c1 = foo.c1 AND bar.c2 = foo.c2)

多くの場合、これは特にパフォーマンスが高いわけではないことに注意してください。

4
Larry Lustig
    SELECT ...
      FROM foo
INNER JOIN (SELECT ...many tuples of a/b values...) AS results
        ON results.a = foo.a
       AND results.b = foo.b

あなたが探しているものは?

3
Stefan H

連結を使用すると、これはPostgreSQLで機能します。

SELECT a,b FROM foo WHERE a||b IN (SELECT a||b FROM bar WHERE condition);

UPDATE foo SET x=y WHERE a||b IN (SELECT a||b FROM bar WHERE condition);
2
Toto

テーブルに既に存在する値のタプルを必要としないソリューションが必要な場合は、リスト内の関連するテーブルの値とアイテムを連結し、「IN」コマンドを使用できます。

Postgresでは、これは次のようになります。

SELECT * FROM foo WHERE a || '_' || b in ('Hi_there', 'Me_here', 'Test_test');

SQLでは、次のように見えると思います。

SELECT * FROM foo WHERE CONCAT(a, "_", b) in ('Hi_there', 'Me_here', 'Test_test');

0
mobeetsatwork

Firebirdは次の連結式を使用します。

SELECT a、b FROM foo WHERE a || b IN(SELECT a || b FROM bar WHERE条件);

0
muaddibx

JOINSおよびINTERSECTSINの代替としては正常に機能しますが、NOT INの代替としてそれほど明確ではありません。たとえば、TableAから行を挿入します。 TableBTableBにまだ存在しない場合、両方のテーブルのPKが複合である場合。

現在、SQL Serverで上記の連結方法を使用していますが、あまりエレガントなソリューションではありません。

0
Simon