Kev*_*vin 5 sql-server aggregate window-functions group-by sql-server-2016
仅当分区中存在负值时,我才需要将值相加。如果分区中没有负值,它应该只输出行。
这就是我现在所拥有的。初始数据作为 CTE 提供。
数据管理语言
;with ledger as (
select accountId, type, amount
from (
values
(1, 'R', -10)
,(1, 'V', 10)
,(1, 'R', 30)
,(2, 'R', 20)
,(2, 'R', -5)
,(2, 'V', 5)
,(3, 'R', 20)
,(3, 'R', 30)
) x (accountId, type, amount)
)
,b as ( --identifies accountid, type with negatives
select
accountid
,type
from ledger
group by accountid, type
having min(amount) < 0
)
,onlyPositives as (
select
l.accountid
,l.type
,l.amount
from ledger l
left join b on b.accountid = l.accountid
and b.type = l.type
where b.accountid is null
)
,aggregatedNegatives as (
select
l.accountid
,l.type
,amount = sum(l.amount)
from ledger l
inner join b on b.accountid = l.accountid
and b.type = l.type
group by l.accountid, l.type
)
select accountid, type, amount
from onlyPositives
union all
select accountid, type, amount
from aggregatedNegatives
Run Code Online (Sandbox Code Playgroud)
我期待这样的输出,并且上面的查询输出正确。
1, R, 20 (summed because -10+30=20)
1, V, 10 (left alone)
2, R, 15 (summed because 20-5=15)
2, V, 5 (left alone)
3, R, 20 (left alone)
3, R, 30 (left alone)
Run Code Online (Sandbox Code Playgroud)
到目前为止,这个查询看起来很糟糕,而且感觉不必要地复杂。是否有我可以编写但我忽略的更简单的查询?
这是该问题的一个细微变化:如果为正,则对所有项目求和。如果为负,则返回每一个
reextester -> https://rextester.com/EZRT33825
您可以在使用窗口函数后完成您的任务,但如果您在很多行上运行此查询,我无法对性能做出任何承诺。这个想法是计算每个分区的总和、最小值和一个无序的行号。保留最小值 > 0 的所有行,但如果最小值 < 0,则仅保留分区的第一行。
-- put data into temp table for illustration purposes
select accountId, type, amount into #t220618
from (
values
(1, 'R', -10)
,(1, 'R', 30)
,(1, 'V', 10)
,(2, 'R', 20)
,(2, 'R', -5)
,(2, 'V', 5)
,(3, 'R', 20)
,(3, 'R', 30)
) x (accountId, type, amount);
SELECT
accountId
, type
, CASE WHEN part_min < 0 THEN part_sum else amount END amount
FROM (
SELECT
accountId
, type
, amount
, SUM(amount) OVER (PARTITION BY accountId, type) part_sum
, MIN(amount) OVER (PARTITION BY accountId, type) part_min
, ROW_NUMBER() OVER (PARTITION BY accountId, type ORDER BY (SELECT NULL)) part_rn
FROM #t220618
) q
WHERE q.part_min > 0 OR (part_min < 0 AND part_rn = 1);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
472 次 |
最近记录: |