如何在不增加返回的行数的情况下修改此查询?

时间:2010-08-04 21:40:13

标签: sql sql-server-2008

我在查询中有一个子选择,看起来像这样:

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

但这样做是错误的,因为如果同一个ID存在0型和1型对象,则会增加查询返回的行数,这是不可接受的。所以我需要的是某种子选择,它将为每个不同的ID返回1行,其中“1-type exists”列和“0-type exists”列。我不知道如何在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 个答案:

答案 0 :(得分:3)

在一般情况下,您将使用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;

答案 1 :(得分:2)

而不是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 ...

执行相同的操作