我想在一个表中找到基于两个字段(ContractState,TransID)没有匹配记录的数据。
例如,假设这个数据集(实际上,所有数据集包含数百条记录,我只包括一些):
AccountNbr ContractState TransID Product
3335477 AL 80079 DPPO, DHMO
3335477 AL 80080 PPO
3335477 AR 80079 DPPO, DHMO
3335477 AR 80080 PPO
这应返回0条记录,因为AL有2条记录(每条TransID一条记录),AR记录为2条记录。
但是,给定以下数据集:
AccountNbr ContractState TransID Product
3335477 AL 80079 DPPO, DHMO
3335477 AL 80080 PPO
3335477 DE 80079 DHMO
3335477 WA 80080 DHMO
我想只返回以下数据集:
AccountNbr ContractState TransID Product
3335477 DE 80079 DHMO
3335477 WA 80080 DHMO
因为每个州只有1个TransID。
我有这段代码,但它也包含匹配数据的记录:
SELECT
'tblSQLContractState' as TableName,
TransID,
ContractState,
Product,
COUNT(*) AS [NumOfMessage]
FROM tblSQLContractState
WHERE TransID IN (80079, 80080)
GROUP BY
TransID,
ContractState,
Product
HAVING COUNT(*) = 1
答案 0 :(得分:1)
使用窗口功能。对于您提供的数据,这应该有效:
select cs.*
from (select cs.*,
count(*) over (partition by AccountNbr, ContractState) as cnt
from tblSQLContractState cs
where TransID IN (80079, 80080)
) cs
where cnt = 1;
答案 1 :(得分:1)
您可以使用NOT EXISTS
选择记录中包含此TransId
但不包含此ContractState
的记录的记录:
SELECT
'tblSQLContractState' as TableName,
cs.AccountNbr, cs.ContractState, cs.TransID, cs.Product
FROM tblSQLContractState cs
WHERE cs.TransID IN (80079, 80080)
AND NOT EXISTS -- no other record
(
SELECT 1 FROM tblSQLContractState cs2
WHERE cs2.TransID <> cs.TransID -- with other TransId
AND cs2.ContractState = cs.ContractState -- and this ContractState
)
NOT EXISTS
在SQL-Server中非常有效,可以轻松修改/扩展。另一个优点是您可以选择所有列而不是GROUP BY
。
答案 2 :(得分:1)
您的查询已结束。但是你想要每个ContractState
一个结果行 - 而且你也想知道这个属性的记录数(聚合COUNT(*)
)。因此,请从Product
子句中删除TransID
和GROUP BY
。
由于它只是您想要显示的行数为1的组合,因此您可以使用MIN(Product)
或MAX(Product)
来获取相关产品。与TransID
相同。
SELECT
'tblSQLContractState' as TableName,
MAX(TransID) AS TransID,
ContractState,
MAX(Product) AS Product,
COUNT(*) AS [NumOfMessage]
FROM tblSQLContractState
WHERE TransID IN (80079, 80080)
GROUP BY ContractState
HAVING COUNT(*) = 1;
戈登的答案更直接,更具普遍用途。在我看来,这是解决这个问题的自然方式。我只想表明你的查询非常接近: - )
更新:蒂姆的回答也非常好。 (当我输入我的时候不存在。)他是对的;所有你想知道的是,是否存在ContractState的另一条记录,因此一个exists子句是合适的。