如果他们没有PaymentUid和NO ProcessStatus.value('/ CPI / @ ProcessItem)[1]'...关系,并且还选择'No-Matched-Payments',那么目的是返回所有'未处理'的TransactionSets 'TransactionSets,如果他们有任何PaymentUid和任何ProcessStatus.value('/ CPI / @ ProcessItem)[1]'...关系。
SUM函数看起来很笨,并且在遇到any或none时不允许SQL退出。因此,它看起来效率低下,而且阅读和处理至少相当笨拙。有没有办法用像EXIST这样的东西来写这个?
select ts.TransactionSetUid
from TransactionSet ts
join TransactionHeader eh on ts.TransactionSet = eh.TransactionSet
join TransactionPayment tp on eh.TransactionHeaderUid = tp.TransactionHeaderUid
left join ServicePayment sp on tp.TransactionPaymentUid = sp.TransactionPaymentUid
where TransactionStatus in ('Unprocessed', 'No-Matched-Payments')
group by ts.TransactionSet
having (TransactionStatus = 'Unprocessed'
and SUM( CASE WHEN sp.TransactionItem is null THEN 0 ELSE 1 END) = 0
and SUM( CASE WHEN tp.ProcessStatus.value('(/CPI/@ProcessItem)[1]', 'varchar(50)') IS NULL THEN 0 ELSE 1 END) = 0)
or (ts.RuleStatus = 'No-Matched-Payments'
and (SUM( CASE WHEN sp.TransactionItem is null THEN 0 ELSE 1 END) <> 0
or SUM( CASE WHEN tp.ProcessStatus.value('(/CPI/@ProcessItem)[1]', 'varchar(50)') IS NULL THEN 0 ELSE 1 END) <> 0))
更新回答问题。 TransactionSet与其他表之间的关系是一对多。可能有许多TransactionPayment记录,但查询仅涉及在(/ CPI / @ processItem)[1]处具有xml节点的ProcessStatus.value。但是使用ServicePayment,任何非null的TransactionItem都可以。
据我所知,由于SUM功能,group by只在那里。目的是标记满足两个条件之一的任何TransactionSet。
The first condition is:
the Transaction Status is 'Unprocessed'
and
there are no Process Status values
and
there are no Transaction Items.
The second condition is:
the Transaction Status is 'No-Matched-Payments'
and
there is at least one Process Status value
or
there is at least one Transaction Item.
因此,查询被设置为使用SUM来计算ServicePayment上的左连接出现的次数为NULL或者当TransactionPayment中的XML值不包含'/ CPI / @ processItem'时。
在我看来,查询可以改为使用EXIST或其他一些机制来短路测试条件,而不是使用SUM。 SUM的值并不重要,它只需要知道是否至少有一个或者是否有。
- 谢谢大家:我知道我不是一个数据库专家,而且我已经用七个C(C,C ++,C#,Java等)编程了很长时间,以至于我有时会忘记SQL是不是命令式语言,或者更可能的是,我只是不用声明性的术语来思考。
答案 0 :(得分:0)
我觉得这样的事情可以解决问题:
select ts.TransactionSetUid
from TransactionSet ts
where CASE WHEN EXISTS(SELECT * FROM TransactionHeader eh
join TransactionPayment tp on eh.TransactionHeaderUid = tp.TransactionHeaderUid
left join ServicePayment sp on tp.TransactionPaymentUid = sp.TransactionPaymentUid
where ts.TransactionSet = eh.TransactionSet and
(
sp.TransactionItem is not null or
tp.ProcessStatus.value('(/CPI/@ProcessItem)[1]', 'varchar(50)') IS not NULL
)
) THEN 1 ELSE 0 END =
CASE TransactionStatus
WHEN 'Unprocessed' THEN 0
WHEN 'No-Matched-Payments' THEN 1
END
也就是说,我已将EXISTS
签入以测试任一条件并将其放入CASE
表达式中,以便我们不必将其写出两次我们想要的结果(Unprocessed
和No-Matched-Payments
)。
我还制作了第二个CASE
表达式,以返回0,1或NULL
,这样如果TransactionStatus
是其他内容,则无关紧要结果EXISTS
产生。
我希望我在这里遵循正确的0/1,true / false和/或NULL / NOT NULL逻辑链 - 如果它不是100%,那么它有希望只是调整这些选项。我还假设我可以将TransactionSet
以外的所有表格移到EXISTS
- TransactionHeader
可能必须留在外面TransactionStatus
如果那里<em>
1}}来自。
如果这不正确,您应该在问题中添加简单表格和样本数据,以及预期结果。
答案 1 :(得分:0)
是的,这可能有用...... - 您的查询未包含select distinct,但如果这会产生重复的TransactionSetUid
,请添加关键字distinct
...
select [distinct] ts.TransactionSetUid from TransactionSet ts
join TransactionHeader th
on th.TransactionSet = ts.TransactionSet
join TransactionPayment tp
on tp.TransactionHeaderUid = th.TransactionHeaderUid
where not exists
( Select * from ServicePayment
Where TransactionPaymentUid = tp.TransactionPaymentUid
and tp.ProcessStatus.value(
'(/CPI/@ProcessItem)[1]', 'varchar(50)') IS NULL
and TransactionStatus = 'Unprocessed')
Or exists
( Select * from ServicePayment
Where TransactionPaymentUid = tp.TransactionPaymentUid
and ts.RuleStatus = 'No-Matched-Payments'
and tp.ProcessStatus.value(
'(/CPI/@ProcessItem)[1]', 'varchar(50)') IS not NULL
and ts.RuleStatus = 'No-Matched-Payments')