Где col1, col2 в ( ... ) [подзапрос SQL с использованием составного первичного ключа]

дана таблица 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 ответов


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


ваш синтаксис очень близок к стандартному 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>), объединенные значения и т. д.


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

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

это работает!


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

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

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


    SELECT ...
      FROM foo
INNER JOIN (SELECT ...many tuples of a/b values...) AS results
        ON results.a = foo.a
       AND results.b = foo.b

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


С конкатенацией, это работает с 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);

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


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

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


СУБД Firebird использует эту формулу конкатенации:

выберите a, b из foo, где a / / b в (выберите a / / b из бара, где условие);