memilih di mana dua kolom berada dalam satu set

35

Ini mungkin pertanyaan konyol, dan kecurigaan saya adalah saya tidak bisa melakukan ini, tetapi apakah ada konstruksi dalam SQL yang memungkinkan saya melakukan sesuatu seperti berikut:

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

Saya ingin memilih data di mana dua kolom berada dalam satu set pasangan.

Saya ingin menghindari menggunakan subquery, jika memungkinkan.

James
sumber

Jawaban:

49

Apakah ada konstruk dalam SQL yang memungkinkan saya melakukan sesuatu seperti berikut:

Ya, hampir persis seperti yang Anda tulis. Masukkan saja col1, col2tanda kurung:

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

Namun jika Anda mencobanya dalam DBMS, Anda mungkin menemukan bahwa itu tidak berhasil. Karena tidak semua DBMS menerapkan semua fitur dari standar SQL (yang berkembang). Ini berfungsi di versi terbaru dari Oracle, MySQL, Postgres, DB2 dan HSQLDB (itu tidak dioptimalkan dengan baik di MySQL dan tidak menggunakan indeks, jadi itu harus dihindari di sana kecuali jika mereka memperbaikinya di 5.7).

Lihat dokumentasi MySQL tentang INoperator dan dokumentasi Postgres tentang konstruktor Row . Dua nilai * (atau lebih) dalam tanda kurung disebut konstruktor baris .

Cara lain yang mengekspresikan ide yang sama:

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

Keduanya bekerja di Postgres dan DB2 (afaik). Yang terakhir dapat dimodifikasi untuk bekerja di SQL Server, juga:

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

Itu juga dapat dimodifikasi untuk bekerja di mana saja, dengan menempatkan nilai ke dalam tabel (sementara atau permanen) terlebih dahulu:

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

Dan selalu ada jalan panjang atau mengubah INke ekspresi panjang dengan ORyang harus bekerja di mana-mana:

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

*: Ini sebenarnya bisa hanya satu nilai, dengan ROW(v), lihat dokumen Postgres.

ypercubeᵀᴹ
sumber
Di mana saya dapat menemukan dokumentasi WHERE (x, y) IN (a,b)? Saya menggunakan MySql. Mungkin saya tidak tahu apa sebutan konstruk ini.
Robert Rocha
1
@RobertRocha lihat tautan yang saya tambahkan. Ini disebut konstruktor baris: MySQL:IN dan Postgres: Konstruktor Baris
ypercubeᵀᴹ
Ada juga WHERE EXISTS (SELECT t.col1, t.col2 [FROM DUAL] INTERSECT VALUES(val1, val2), (…, …), …).
Andriy M
-4
SELECT * 
FROM   dbo.Table1 A
WHERE  (CAST(Column1 AS VARCHAR(max)) + '-' + CAST(Column2 AS varchar(max)))
NOT IN (SELECT (CAST(Column1 AS VARCHAR(max)) 
                + '-' 
                + CAST(Column2 AS varchar(max))) 
        FROM Table2)
Muhammad Zia Ul Islam
sumber
2
Itu tidak akan bekerja dengan andal
a_horse_with_no_name
2
Iya nih. Selain inefisiensi, itu tidak akan dapat membedakan antara 'a-b', 'c'dan 'a', 'b-c'. Dan itu akan gagal total untuk semua jenis yang tidak dapat dikonversi varchar(max).
ypercubeᵀᴹ