我想写一个查询来更新基于以下内容的表:
假设我们有下表
Name |Account |Currency |Balance |
Sahil |Account1 |USD |40,000 |
Rohan |Account2 |USD |30,000 |
Mohit |Account3 |USD |20,000 |
Ronak |Account4 |USD |10,000 |
John |Account5 |EUR |50,000 |
Ram |Account6 |EUR |40,000 |
我想总共扣除$ 90,000。首先,我只从货币为美元的帐户中扣除,因为我要扣除的金额是美元。其次,我要扣除的方法是从金额最高的帐户开始。
在我的示例中,我从account1
开始并扣除40,000,依此类推。按照示例,在扣除之后,我应该在account4以外的所有帐户中都用尽了所有金额。扣除后的表格如下所示:
Name |Account |Currency |Balance |
Sahil |Account1 |USD | 0 |
Rohan |Account2 |USD | 0 |
Mohit |Account3 |USD | 0 |
Ronak |Account4 |USD |10,000 |
John |Account5 |EUR |50,000 |
Ram |Account6 |EUR |40,000 |
欧元也一样。
是否可以编写通用查询,其中货币是我的钥匙?
我看到的一个选择是编写一个游标,并遍历按给定货币过滤的记录,这些记录按金额按降序排列。
答案 0 :(得分:2)
好问题。如果您可以访问<div class="video-wrapper" style="padding-top: 75%;">
<div class="thumbnail-outer-container">
<div class="thumbnail-inner-container">
<a href="#" class="yt-hd-thumbnail yt-hd-thumbnail-darken">
<img src="https://i.ytimg.com/vi/xxxxxxxxxxx/hqdefault.jpg">
</a>
<iframe id="youtube_iframe" src="https://www.youtube.com/embed/xxxxxxxxxxx?feature=oembed&enablejsapi=1&origin=https://safe.txmblr.com&wmode=opaque" allow="autoplay; encrypted-media" allowfullscreen="" name="fitvid0" class="yt-hd-thumbnail" frameborder="0"></iframe>
</div>
</div>
</div>
或LEAD
函数,则要容易得多,但是直到SQL 2012才添加这些函数。
我的镜头:
https://dbfiddle.uk/?rdbms=sqlserver_2012&fiddle=4a233d6088d885940d800477077009ba
我跳过了设置。看看小提琴就明白了。
LAG
那给了我们。
Name | Account | Currency | Balance | deductBalance :---- | :-------- | :------- | ------: | ------------: Sahil | Account1 | USD | 40000 | 0 Rohan | Account2 | USD | 30000 | 0 Mohit | Account3 | USD | 20000 | 0 Mohit | Account99 | USD | 20000 | 20000 Ronak | Account4 | USD | 10000 | 10000
db <>提琴here
注意::我在Mohit / Account99中添加了2万美元的额外行,以表示这如何处理可能具有相同余额的行。在测试中,我还为使用EUR的Ronak / Account4添加了额外的一行,以便您可以看到该查询如何也不会对名称和帐户相同但货币不同的人进行排序。我不知道您的数据是否确实有这种可能性,但是可以考虑。
答案 1 :(得分:1)
您可以使用相关子查询获得balance
排序的所有“上一个”帐户的总和。添加当前的balance
并使用CASE ... END
来检查此结果是否小于或等于您要减去的值。如果是,则新余额将为0
,否则是结果减去要减去的值。使用相同的子查询,您可以将UPDATE
限制为总和小于或等于要减去的值的那些行,以使“低”帐户不会受到影响。但是,请不要在此处添加当前的balance
来获得“一个”,从而确定边界。
UPDATE elbat
SET balance = CASE
WHEN coalesce((SELECT sum(t2.balance)
FROM elbat t2
WHERE t2.currency = elbat.currency
AND (t2.balance > elbat.balance
OR t2.balance = elbat.balance
AND t2.%%physloc%% > elbat.%%physloc%%)),
0) + balance <= 90000 THEN
0
ELSE
coalesce((SELECT sum(t2.balance)
FROM elbat t2
WHERE t2.currency = elbat.currency
AND (t2.balance > elbat.balance
OR t2.balance = elbat.balance
AND t2.%%physloc%% > elbat.%%physloc%%)),
0) + balance - 90000
END
FROM elbat
WHERE currency = 'USD'
AND coalesce((SELECT sum(t2.balance)
FROM elbat t2
WHERE t2.currency = elbat.currency
AND (t2.balance > elbat.balance
OR t2.balance = elbat.balance
AND t2.%%physloc%% > elbat.%%physloc%%)),
0) <= 90000;
要处理余额相同的帐户,需要使用第二个条件。您没有告诉表中是否存在唯一列。我使用了未记录的%%physloc%%
伪列作为代理。它描述了行的物理位置。这似乎可行,但可能很危险。因为它没有记录,所以我无法说在执行UPDATE
的过程中是否会受到影响。如果可能的话,应将其替换为表格中唯一的列。
答案 2 :(得分:0)
您需要一个累加的总和,这比SQL Server 2008中所需要的要痛苦得多。其余的只是更新和一些算术运算。逻辑看起来像这样:
with toupdate as (
select t.*,
(select sum(t2.balance)
from t t2
where (t.currency = 'USD' and t2.currency = 'USD' and t2.balance <= t.balance) or
(t.currency = 'EUR' and t2.currency = 'USD') or
(t.currency = 'EUR' and t2.currency = 'EUR' and t2.balance <= t.balance)
) as running_balance
from t
)
update toupdate
set balance = (case when running_balance < 40000 then 0
else running_balance - 40000
end)
where running_balance - balance < 40000;