SQL: выберите записи, в которых ВСЕ соединенные записи удовлетворяют некоторому условию. - PullRequest
6 голосов
/ 26 июля 2010

Как я могу написать запрос SQL, который возвращает запись, только если ВСЕ связанные записи в объединенной таблице удовлетворяют некоторому условию.

Например, если A имеет много B, я хочу ВЫБРАТЬ * ОТ А, ГДЕ все связанные B для данного A имеют B.some_val> значение

Я знаю, что это, вероятно, довольно простой вопрос, так что спасибо за любую помощь. Кроме того, если это имеет значение, я использую postgres.

Sam

Ответы [ 6 ]

4 голосов
/ 26 июля 2010

Предполагая, что корреляция не требуется, используйте:

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.

2 голосов
/ 26 июля 2010
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)
0 голосов
/ 26 июля 2010

Используйте книжные магазины и книги в качестве примера.

Книжный магазин

bookstoreID, bookID

Book

bookID, цена

IПредположим, вы хотите вернуть все книжные магазины, в которых все книги имеют цену выше 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                                                     
 )
0 голосов
/ 26 июля 2010
select * from a where a.key = b.a_key where b.value > condition
0 голосов
/ 26 июля 2010

Вы хотите, чтобы ВНУТРЕННЕЕ СОЕДИНЕНИЕ:

SELECT
    A.*
FROM
    A
INNER JOIN B
    ON A.identifier = B.identifier
WHERE
    B.some_val > value

Вы хотите убедиться, что существует внешний ключ от A до B или какой-либо другой общий идентификатор.

0 голосов
/ 26 июля 2010

Должно работать следующее:

SELECT *
FROM a
JOIN b ON a.key = b.key AND a.value > b.value

Поскольку это внутреннее объединение *, а не внешнее объединение , записи из A будут включены, только еслиесть записи в B, которые удовлетворяют условию.

Я не использую PostGRE, поэтому не могу гарантировать, что синтаксис является абсолютно правильным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...