Где 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 из бара, где условие);