ГДЕ col1, col2 IN (...) [подзапрос SQL с использованием составного первичного ключа] - PullRequest
35 голосов
/ 07 января 2011

Для таблицы foo с составным первичным ключом (a,b) существует ли допустимый синтаксис для написания запроса, например:

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

Если это невозможно, и вы не можете изменить схему, как вы можете выполнить эквивалент выше?

Я также собираюсь разместить здесь термины «составной первичный ключ», «subselect», «sub-select» и «sub-query» для поисковых запросов по этим псевдонимам.

Редактировать : меня интересуют ответы для стандартного SQL, а также ответы, которые будут работать с PostgreSQL и SQLite 3.

Ответы [ 9 ]

26 голосов
/ 07 января 2011
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 bar на select ... many tuples of a/b values ....

Или создайте временную таблицу из select ... many tuples of a/b values ... и используйте ее вместо bar ..

19 голосов
/ 07 января 2011

Ваш синтаксис очень близок к стандартному SQL!

Следующее является действительным ПОЛНЫЙ SQL-92 (как подтверждено валидатором Mimer SQL-92 )

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

Конечно, не каждый продукт SQL поддерживает полный SQL-92 (позор!). Если кому-то хотелось бы увидеть этот синтаксис поддерживаемым в Microsoft SQL Server, он может проголосовать за него здесь .

Еще одна конструкция SQL-92, которая более широко поддерживается (например, Microsoft SQL Server и Oracle), - INTERSECT, например.

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

Обратите внимание, что эти конструкции правильно обрабатывают значение NULL, в отличие от некоторых других предложений, например, здесь. использующие EXISTS (<equality predicates>), объединенные значения и т. д.

9 голосов
/ 01 августа 2012

Вы сделали одну очень маленькую ошибку. Вы должны поставить a, b в скобках.

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

Это работает!

4 голосов
/ 07 января 2011

Синтаксис IN, который вы предложили, не является допустимым SQL. Решение, использующее EXISTS, должно работать на всех разумно совместимых СУБД SQL:

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

Имейте в виду, что это часто не особенно эффективно.

3 голосов
/ 07 января 2011
    SELECT ...
      FROM foo
INNER JOIN (SELECT ...many tuples of a/b values...) AS results
        ON results.a = foo.a
       AND results.b = foo.b

Это то, что вы ищете?

2 голосов
/ 07 января 2011

С конкатенацией это работает с 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);
0 голосов
/ 14 октября 2013

Firebird использует следующую формулу объединения:

ВЫБРАТЬ a, b ОТ ФУ ГДЕ a || b IN (ВЫБРАТЬ a || b ИЗ ПРАВА, ГДЕ условие);

0 голосов
/ 09 ноября 2012

Если вам нужно решение, которое не требует кортежей значений, уже существующих в таблице, вы можете объединить соответствующие значения таблицы и элементы в вашем списке, а затем использовать команду 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 голосов
/ 05 апреля 2011

JOINS и INTERSECTS прекрасно работают вместо IN, но они не так очевидны, как замена NOT IN, например: вставка строк из TableA в TableB там, где они находятсяуже существует в TableB, где PK в обеих таблицах является составным.

В настоящее время я использую описанный выше метод конкатенации в SQL Server, но это не очень элегантное решение.

...