Как я могу записать SQL-запрос, который возвращает запись, только если ВСЕ связанные записи в объединяемой таблице удовлетворяют некоторое условие.
Например, если A имеет много B, я хочу ВЫБРАТЬ * ИЗ, ГДЕ все имели отношение, B для данного A имеют B.some_val> значение
Я знаю, что это - вероятно, довольно основной вопрос, так спасибо за любую справку. Кроме того, если это имеет значение, я использую пост-ГРЭС.
Sam
Предполагая, что корреляция не нужна, используйте:
SELECT a.*
FROM A a
WHERE EXISTS(SELECT NULL
FROM B b
HAVING MIN(b.some_val) > a.val)
Если корреляция нужна:
SELECT a.*
FROM A a
WHERE EXISTS(SELECT NULL
FROM B b
WHERE b.id = a.id
HAVING MIN(b.some_val) > a.val)
EXISTS
оценивается по булеву числу, основанному на первом совпадении - это делает его быстрее, чем, скажем, использование IN, и - в отличие от использования JOIN - не будет дублировать строки. Часть SELECT не имеет значения - вы можете изменить ее на EXISTS SELECT 1/0 ...
, и запрос все равно будет работать, хотя и будет очевидная ошибка деления на ноль.
Подзапрос внутри EXISTS
использует агрегатную функцию MIN для получения наименьшего значения B.some_val - если это значение больше значения a.val, то a.val меньше всех значений b. Пункт WHERE
нужен только для корреляции - агрегатные функции можно использовать только в пункте HAVING
.
select * from A
where -- at least one record in B is greater than some_val
exists (select null from B
where B.some_val > :value
and A.join_column = B.join_column)
and -- no records in B are not greater than some_val
not exists (select null from B
where B.some_val <= :value
and A.join_column = B.join_column)
Следующее должно работать:
SELECT *
FROM a
JOIN b ON a.key = b.key AND a.value > b.value
Поскольку это выполняет внутреннее соединение , а не внешнее соединение , записи из A будут только будут включены, если у них есть записи в B, удовлетворяющие условию.
Я не использую PostGRE, поэтому не могу гарантировать, что синтаксис в точности правильный.
Вам нужно ВНУТРЕННЕЕ СОЕДИНЕНИЕ:
SELECT
A.*
FROM
A
INNER JOIN B
ON A.identifier = B.identifier
WHERE
B.some_val > value
Вы захотите убедиться, что существует внешний ключ от A до B или какой-либо другой общий идентификатор.
select * from a where a.key = b.a_key where b.value > condition
Используйте книжные магазины и книги в качестве примера.
bookstoreID, bookID
bookID, цена
Я полагаю, вы хотите вернуть все книжные магазины, в которых все книги имеют цену выше X.
select *
from Bookstore bs1
where bs1.bookstoreID not exist
(
select bs.bookstoreID
from Bookstore bs, Book b
where bs.bookID= b.bookID
b.price < x; -- your value
)