web-dev-qa-db-ja.com

2つの列がセットのどこにあるかを選択する

これはばかげた質問かもしれません、そして私の疑いは私がこれを行うことができないということです、しかし私が以下のようなことをすることを可能にするSQLに構成があります:

SELECT whatever WHERE col1,col2 IN ((val1, val2), (val1, val2), ...)

2つの列がペアのセットになっているデータを選択します。

可能であれば、サブクエリの使用を避けたいです。

38
James

SQLに次のようなことを可能にする構文がありますか?

はい、あります。あなたが書いたとおりです。括弧内に_col1, col2_を置くだけです:

_-- works in PostgreSQL, Oracle, MySQL, DB2, HSQLDB 
SELECT whatever 
FROM t                               --- you missed the FROM
WHERE (col1, col2)                    --- parentheses here
       IN ((val1a, val2a), (val1b, val2b), ...) ;
_

ただし、DBMSで試してみると、機能しない場合があります。すべてのDBMSが(進化する)SQL標準のすべての機能を実装しているわけではないためです。これは、Oracle、MySQL、Postgres、DB2、およびHSQLDBの最新バージョンで機能します(MySQLでは十分に最適化されておらず、インデックスを使用していなかったため、5.7で修正しない限り、回避する必要があります)。

IN operator に関するMySQLのドキュメントと Rowコンストラクタ に関するPostgresのドキュメントを参照してください。括弧内の2つ(またはそれ以上)の値は、row-constructorと呼ばれます。

同じ考えを表す他の方法:

_-- works in PostgreSQL, DB2
SELECT whatever 
FROM t 
WHERE (col1, col2) 
       IN ( VALUES (val1a, val2a), (val1b, val2b), ...) ;

SELECT t.whatever 
FROM t 
  JOIN 
    ( VALUES (val1a, val2a), (val1b, val2b), ...) AS x (col1, col2)
      ON (x.col1, x.col2) = (t.col1, t.col2) ;
_

どちらもPostgresとDB2(afaik)で動作します。最後の1つは、SQL Serverでも機能するように変更できます。

_-- works in PostgreSQL, DB2, SQL Server
SELECT t.whatever 
FROM t 
  JOIN 
    ( VALUES (val1a, val2a), (val1b, val2b), ...) AS x (col1, col2)
      ON  x.col1 = t.col1
      AND x.col2 = t.col2 ;
_

また、値を(一時的または永続的)テーブルに最初に配置することで、どこでも機能するように変更することもできます。

_-- works everywhere
CREATE TABLE values_x
( col1  ...,
  col2  ...) ;

-- use appropriate for the DBMS syntax here
INSERT INTO values_x (col1, col2)
VALUES (val1a, val2a), (val1b, val2b), ... ;

SELECT t.whatever 
FROM t 
  JOIN values_x  x 
      ON  x.col1 = t.col1
      AND x.col2 = t.col2 ;

DROP TABLE values_x ;
_

そして、常に長い道のり、またはINORを使用した長い式に変換すると、どこでも機能するはずです。

_-- works in all SQL DBMS
SELECT whatever 
FROM t  
WHERE col1 = val1a AND col2 = val2a
   OR col1 = val1b AND col2 = val2b
   ---
   ;
_

*:ROW(v)を使用すると、実際には1つの値にすることができます。Postgresのドキュメントを参照してください。

51
ypercubeᵀᴹ