我在带有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
有没有办法让我说'从第一个查询中提供所有内容但是从第二个查询中排除所有内容?'
此外,任何有关清理我的陈述的建议都将受到赞赏。我并没有声称自己擅长这一点。
谢谢!
答案 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;