เลือกตำแหน่งของคอลัมน์สองชุด


35

นี่อาจเป็นคำถามงี่เง่าและความสงสัยของฉันคือฉันไม่สามารถทำได้ แต่มีโครงสร้างใน SQL ที่จะให้ฉันทำสิ่งต่อไปนี้:

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

ฉันต้องการเลือกข้อมูลที่มีสองคอลัมน์อยู่ในชุดของคู่

ฉันต้องการหลีกเลี่ยงการใช้แบบสอบถามย่อยถ้าเป็นไปได้

คำตอบ:


48

มีโครงสร้างใน 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)

ดูเอกสาร MySQL เกี่ยวกับINผู้ประกอบการและเอกสารเกี่ยวกับ Postgres ก่อสร้างแถว ทั้งสอง * (หรือมากกว่า) ค่าในวงเล็บจะเรียกว่าเป็นแถวคอนสตรัค

วิธีอื่น ๆ ที่แสดงความคิดเดียวกัน:

-- 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) อันสุดท้ายสามารถปรับเปลี่ยนให้ทำงานใน 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 ;

และยังมีทางยาวหรือแปลงINเป็นนิพจน์แบบยาวORที่ควรทำงานได้ทุกที่:

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

*: จริง ๆ แล้วมันอาจเป็นเพียงค่าเดียวกับROW(v)ดู Postgres เอกสาร


ฉันจะหาเอกสารเกี่ยวกับได้WHERE (x, y) IN (a,b)ที่ไหน ฉันใช้ MySql บางทีฉันไม่รู้ว่าโครงสร้างนี้เรียกว่าอะไร
Robert Rocha

1
@RobertRocha เห็นลิงค์ที่ฉันเพิ่ม มันเรียกว่าตัวสร้างแถว: MySQL:INและPostgres: Row Constructors
ypercubeᵀᴹ

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)

2
ที่ไม่ไปทำงานได้อย่างน่าเชื่อถือ
a_horse_with_no_name

2
ใช่. นอกจากนี้การขาดประสิทธิภาพก็จะไม่สามารถที่จะแยกความแตกต่างระหว่างและ'a-b', 'c' 'a', 'b-c'และมันจะล้มเหลวอย่างน่าสังเวชสำหรับประเภทใด ๆ ที่ไม่สามารถแปลงเป็นvarchar(max)ได้
ypercubeᵀᴹ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.