Как изменить этот запрос, не увеличивая количество возвращаемых строк? - PullRequest
1 голос
/ 05 августа 2010

У меня есть дополнительный выбор в запросе, который выглядит примерно так:

left outer join
  (select distinct ID from OTHER_TABLE) as MYJOIN
on BASE_OBJECT.ID = MYJOIN.ID

Это довольно просто. Проверяет, существует ли определенное отношение между основным объектом, к которому запрашивается, и объектом, представленным OTHER_TABLE, в зависимости от того, является ли MYJOIN.ID нулевым в рассматриваемой строке.

Но теперь требования немного изменились. В OTHER_TABLE есть еще одна строка, которая может иметь значение 1 или 0, и запрос должен знать, существует ли отношение между первичным для значения 1, а также существует ли оно для значения 0. Очевидные решения это поставить:

left outer join
  (select distinct ID, TYPE_VALUE from OTHER_TABLE) as MYJOIN
on BASE_OBJECT.ID = MYJOIN.ID

Но это было бы неправильно, поскольку если объекты 0-типа и 1-типа существуют для одного и того же идентификатора, это увеличит количество строк, возвращаемых запросом, что недопустимо. Так что мне нужен какой-то подвыбор, который будет возвращать 1 строку для каждого отдельного идентификатора со столбцом «1-тип существует» и столбцом «0-тип существует». И я понятия не имею, как кодировать это в SQL.

Например, для следующей таблицы

ID   | TYPE_VALUE
_________________
1    | 1
3    | 0
3    | 1
4    | 0

Я бы хотел увидеть такой набор результатов:

ID   | HAS_TYPE_0 | HAS_TYPE_1
______________________________
1    | 0          | 1
3    | 1          | 1
4    | 1          | 0

Кто-нибудь знает, как я могу настроить запрос для этого? Надеюсь, с минимумом уродливых хаков?

Ответы [ 2 ]

3 голосов
/ 05 августа 2010

В общем случае вы должны использовать EXISTS:

SELECT DISTINCT ID,
    CASE WHEN EXISTS (
            SELECT * FROM Table1 y 
            WHERE y.TYPE_VALUE = 0 AND ID = x.ID) 
        THEN 1 
        ELSE 0 END AS HAS_TYPE_0,
    CASE WHEN EXISTS (
            SELECT * FROM Table1 y
            WHERE y.TYPE_VALUE = 1 AND ID = x.ID) 
        THEN 1 
        ELSE 0 END AS HAS_TYPE_1
FROM Table1 x;

Если у вас очень большое количество элементов в таблице, это не будет работать так хорошо - эти вложенные подвыборы часто целуютсясмерти, когда дело доходит до исполнения.

В вашем конкретном случае вы также можете использовать GROUP BY и MAX () и MIN () для ускорения:

SELECT 
     ID,
     CASE WHEN MIN(TYPE_VALUE) = 0 THEN '1' ELSE 0 END AS HAS_TYPE_0,
     CASE WHEN MAX(TYPE_VALUE) = 1 THEN '1' ELSE 0 END AS HAS_TYPE_1
FROM Table1
GROUP BY ID;
2 голосов
/ 05 августа 2010

вместо select distinct ID, TYPE_VALUE from OTHER_TABLE использовать

select ID,  
MAX(CASE WHEN TYPE_VALUE =0 THEN 1 END) as has_type_0,  
MAX(CASE WHEN TYPE_VALUE =1 THEN 1 END) as has_type_1  
from OTHER_TABLE
GROUP BY ID;

Вы можете сделать то же самое, используя PIVOT opearator ...

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