SQL添加额外的子查询以排除主查询的结果

时间:2017-06-15 15:16:34

标签: sql sql-server database

我在带有2个表的SQL 2008数据库上运行报告。父表是帐户,子表是合同,它们链接在唯一标识符字段 - AccountID。

我的目标是根据合同的类型提取所有帐户和合同。

我现在有这个问题:

Select Account.*, C.* from Account

Left Join Contracts C
on C.AccountID=Account.AccountId

Where 

(Case when C.T1 = 'TYPE1' or C.T1 = 'TYPE2' or C.T1 = 'TYPE3' or C.T1 = 'TYPE4' or C.T1 = 'TYPE5' or C.T1 = 'TYPE6' Then 0 Else 1 END) = 0 
and EXISTS (Select E.AccountID, E.T1 from Contracts E Where E.AccountID = C.AccountID and (E.T1 LIKE 'TYPE6' and Convert(Date,E.End_Date) = Convert(Date,C.End_Date)))

Order by Account.AccountID

我们的想法是将所有具有合同的帐户拉到T1 = TYPE1-6,但前提是他们有合同,其中T1 = TYPE6。这给出了如下结果:

AccountID   Contract    T1
   1             1       4
   1             2       5
   1             3       6

   2             4       6
   2             5       2
   2             6       6

   3             7       6
   3             8       6
   3             9       6

我需要做的下一件事就是排除只有合同TYPE6 的帐户,我完全迷失了。理想的结果是,我将获得账户1和账户的所有3份合约。 2,但会从结果中删除帐户3。

我的假设是我需要一个额外的查询来提供我不想要的结果。我不完全理解EXCEPT语句,但我觉得可能需要放在这里?

此查询为我提供了不应包含在我的第一个结果中的所有帐户/合同:

Select Account.*, C.* from Account 

Left Join Contracts C
on C.AccountID=Account.AccountId

where
(Case When C.T1 = 'TYPE6' Then 0 Else 1 End) = 0
and NOT EXISTS (Select E.AccountID, E.T1 from Contracts E Where E.AccountID = C.AccountID and E.T1 NOT LIKE '%TYPE6%'and Convert(Date,E.End_Date) = Convert(Date,C.End_Date)) 


Order by Account.AccountID

有没有办法让我说'从第一个查询中提供所有内容但是从第二个查询中排除所有内容?'

此外,任何有关清理我的陈述的建议都将受到赞赏。我并没有声称自己擅长这一点。

谢谢!

2 个答案:

答案 0 :(得分:0)

最后一个条件应该通过测试是否存在另一个不属于类型6的合同(我没有在本地测试)来完成这个技巧。

Select Account.*, C.* from Account

        Left Join Contracts C
        on C.AccountID=Account.AccountId

        Where 

        (Case when C.T1 = 'TYPE1' or C.T1 = 'TYPE2' or C.T1 = 'TYPE3' or C.T1 = 'TYPE4' or C.T1 = 'TYPE5' or C.T1 = 'TYPE6' Then 0 Else 1 END) = 0 
        and EXISTS (Select E.AccountID, E.T1 from Contracts E Where E.AccountID = C.AccountID and (E.T1 LIKE 'TYPE6' and Convert(Date,E.End_Date) = Convert(Date,C.End_Date)))
    AND (C.T1 <> 'TYPE6' OR EXISTS(SELECT * FROM Contracts con WHERE con.AccountId = Account.AccountId AND con.T1 <> 'TYPE6' ))

        Order by Account.AccountID

答案 1 :(得分:0)

您需要有关帐户的信息(无论其任何或所有记录的类型是否为6)。因此,请按帐户ID进行分组并检查您的帐户。

select accountid
from contracts
where t1 between 1 and 6
group by accountid
having count(case when t1 = 6 then 1 end) > 0 -- at least one record of type 6
   and count(case when t1 <> 6 then 1 end) > 0 -- at least one record of type 1 to 5

然后,您可以选择这些帐户的记录:

select * 
from accounts a
join contracts c on c.accountid = a.accountid
where c.t1 between 1 and 6 and c.accountid in (<above query>);

只读一次表的替代方法是使用分析函数COUNT OVER而不是COUNT

select accountid, contract, t1
from
(
  select 
    a.*, c.*,
    count(case when c.t1 = 6 then 1 end) over (partition by c.accountid) as c6,
    count(case when c.t1 <> 6 then 1 end) over (partition by c.accountid) as c12345
  from accounts a
  join contracts c on c.accountid = a.accountid
  where c.t1 between 1 and 6
) mydata
where c6 > 0 and c12345 > 0;