Можно ли сравнить * кортежи * в предложении `WHERE` SQL-запроса?

Можно ли сравнить кортежи (спасибо, a_horse_with_no_name) в WHERE предложение SQL-запроса? Таким образом, я мог бы преобразовать это:

/* This is actually a sub-sub-sub-query in the middle *
 * of an incredibly complex stored procedure.         */
SELECT ISNULL(SUM(DT.DetailField), 0)
FROM   DetailTable DT
WHERE  DT.ForeignKey = ...
AND    EXISTS (/* I know this sub-sub-sub-sub-query *
                * will return at most one row.      */
               SELECT 'X'
               FROM   HeaderTable HT
               WHERE  HT.HeaderKey    = DT.HeaderKey
               AND    HT.HeaderField1 = ...
               AND    HT.HeaderField2 = ...)

На что-то похожее на это:

SELECT ISNULL(SUM(DetailField), 0)
FROM   DetailTable DT
WHERE  DT.ForeignKey = ...
AND    (SELECT HT.HeaderField1, HT.HeaderField2
        FROM   HeaderTable HT
        WHERE  HT.HeaderKey = DT.HeaderKey) = (..., ...)

4 ответа

Решение

Ответ Горана выглядит лучше всего для меня, и я проголосовал за него. Просто чтобы добавить еще один вариант, так как вы используете SQL Server, гибкий способ получить несколько столбцов из подзапросов outer apply, Вы можете сравнить два значения (кортеж), например:

select  *
from    SomeTable t1
outer apply
        (
        select  *
        from    SomeOtherTable t2
        where   t1.Stuff = t2.Unit
        ) sub1
outer apply
        (
        select  *
        from    YetAnotherTable t3
        where   t1.Stuff = t3.jetser
        ) sub2
where   sub1.col1 = sub2.col1
        and sub1.col2 = sub2.col2

Пишу

И (ВЫБЕРИТЕ HT.HeaderField1, HT.HeaderField2
        FROM   HeaderTable HT
        ГДЕ HT.HeaderKey = DT.HeaderKey) = (..., ...)

конечно возможно. По крайней мере, с Oracle и PostgreSQL

Если вы не уверены, что суб-выбор возвращает более одной строки, вы можете даже изменить = в IN

То, что вы ищете, это внутреннее соединение:

SELECT ISNULL(SUM(DetailField), 0)
FROM   DetailTable DT
INNER JOIN HeaderTable HT ON HT.HeaderKey = DT.HeaderKey
WHERE  DT.ForeignKey = ...
AND    HT.HeaderField1 = ...
AND    HT.HeaderField2 = ...)

Кажется, вы пытаетесь сравнить записи, а не таблицы здесь. А на самом деле вы сравниваете результаты запросов.

Это вполне возможно с Oracle и MySQL. Следующий запрос действителен и выполняет работу:

SELECT (SELECT foo, bar FROM wathever) = (SELECT fuu, baz FROM another);

Он сравнивает поля одно с одним и возвращает 1, если они все совпадают (или 0, если они не совпадают). Если подзапросы возвращают более одной строки, это вызовет ошибку SQL. Это выражение может также использоваться в другом месте, как в предложениях WHERE.

Обновление для postgreSQL

Как указал @tsionyx, в PostgreSQL подзапрос не может возвращать несколько столбцов. Возможен возврат типа значения строки:

SELECT (SELECT ROW(foo, bar) FROM wathever) = (SELECT ROW(fuu, baz) FROM another);
Другие вопросы по тегам