根据自定义要求更新表

时间:2018-08-09 20:19:17

标签: sql sql-server-2008

我想写一个查询来更新基于以下内容的表:

假设我们有下表

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  |

欧元也一样。

是否可以编写通用查询,其中货币是我的钥匙?

我看到的一个选择是编写一个游标,并遍历按给定货币过滤的记录,这些记录按金额按降序排列。

3 个答案:

答案 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&amp;enablejsapi=1&amp;origin=https://safe.txmblr.com&amp;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;

db<>fiddle

要处理余额相同的帐户,需要使用第二个条件。您没有告诉表中是否存在唯一列。我使用了未记录的%%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;