вибір місця, де два набір стовпців


35

Це може бути дурним питанням, і я підозрюю, що я не можу цього зробити, але чи є така конструкція в SQL, яка б дозволила мені зробити щось на кшталт наступного:

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

Я хочу вибрати дані, де два стовпці знаходяться в наборі пар.

Я б хотів уникнути використання підзапиту, якщо це можливо.

Відповіді:


49

Чи є в 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), ...) ;

Якщо ви спробуєте це в СУБД, ви можете виявити, що він не працює. Тому що не всі СУБД реалізували всі функції (що розвиваються) стандарту 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. Можливо, я не знаю, як називається ця конструкція.
Роберт Роша

1
@RobertRocha дивіться посилання, які я додав. Він називається конструктором рядків: MySQL:IN та Postgres: Row Constructors
ypercubeᵀᴹ

Там також WHERE EXISTS (SELECT t.col1, t.col2 [FROM DUAL] INTERSECT VALUES(val1, val2), (…, …), …).
Андрій М

-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ᵀᴹ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.