SQL Server:对列的每个组值求和(或差),直到在另一列上满足条件

Posted

技术标签:

【中文标题】SQL Server:对列的每个组值求和(或差),直到在另一列上满足条件【英文标题】:SQL Server : summing (or difference) each group values of a column until a condition is met on another column 【发布时间】:2019-02-19 08:58:44 【问题描述】:

我对 SQL 和使用 SQL Server 2012 还是很陌生。我在下面使用的数据集中有一个示例。它是银行交易和发票金额的会计数据集,具有以下值客户 ID、发票日期、VADEKONTROL 指示发票是否过期-未过期-未发票、BORC 是发票金额、ALACAK 是收到的付款金额和BAKIYE 是总余额。不是发票交易是银行收据。

我想为每个客户做的是从最后一个 BAKIYE 中减去从最后一个条目开始的 BORC 列中的值,直到差值

如果某个客户的BAKIYE的最后一个值为0,也不需要减法。

基本逻辑如上:

    我想选择从 BAKIYE 中减去的条目(直到 BAKIYE 达到 0 或所选条目的总和与 bakiye 之间的差达到 0,无论您如何看待它。

    对最有可能使用 group by 的每个客户选择的条目进行计数和汇总。

编辑:

请记住,如果 BORC 值为 0,则交易为贷方,如果 ALACAK 值为 0,则交易为债务。因此,为了从最后一个开始找到当前余额,我们可能必须从 BAKIYE 中减去 BORC 和 ALACAK 值。

基本上我想要的是从最后一条记录开始的每个客户组:获取 BAKIYE 值的最后一行,从同一行的 BAKIYE 中减去 BORC+ALACAK。重复这一行,直到每个客户的 BAKIYE

我该如何继续解决这个问题?

任何帮助将不胜感激。

ACCID   BDATE       VADEKONTROL     BORC    ALACAK  BAKIYE
------------------------------------------------------------
M01518  12.12.2018  expired         64,51     0,00   64,51
M01518  14.01.2019  expired         69,00     0,00  133,51
M01518  12.02.2019  not expired     69,00     0,00  202,51
M01518  18.02.2019  not invoice      0,00   203,00   -0,49
M01517  14.12.2018  expired         93,49     0,00   93,49
M01517  14.01.2019  expired         93,49     0,00  186,98
M01517  12.02.2019  not expired     93,49     0,00  280,47
M01516  25.12.2018  expired         982,81    0,00  982,81
M01516  21.01.2019  expired         999,59    0,00  1982,40
M01514  11.12.2018  expired          25,10    0,00    25,10
M01514  10.01.2019  not invoice       0,00   25,10     0,00
M01514  14.01.2019  expired          25,10    0,00    25,10
M01514  24.01.2019  not invoice       0,00   25,10     0,00
M01514  11.02.2019  not expired      25,10    0,00    25,10

使用 Dwight 的代码编辑 2 输出:

ACCID   BDATE        VADEKONTROL    BORC    ALACAK  BAKIYE  BAKIYE_less_BORC
M01518  2018-12-12  Vadesi Geçmiş   64,51   0,00    64,51   0,00
M01518  2019-01-14  Vadesi Geçmiş   69,00   0,00    133,51  64,51
M01518  2019-02-12  Vadesi Gelmemiş 69,00   0,00    202,51  NULL
M01518  2019-02-18  FaturaDegil     0,00    203,00  -0,49   NULL
M01517  2018-12-14  Vadesi Geçmiş   93,49   0,00    93,49   0,00
M01517  2019-01-14  Vadesi Geçmiş   93,49   0,00    186,98  93,49
M01517  2019-02-12  Vadesi Gelmemiş 93,49   0,00    280,47  NULL
M01516  2018-12-25  Vadesi Geçmiş   982,81  0,00    982,81  0,00
M01516  2019-01-21  Vadesi Geçmiş   999,59  0,00    1982,40 982,81
M01514  2018-12-11  Vadesi Geçmiş   25,10   0,00    25,10   0,00
M01514  2019-01-10  FaturaDegil     0,00    25,10   0,00    NULL
M01514  2019-01-14  Vadesi Geçmiş   25,10   0,00    25,10   0,00
M01514  2019-01-24  FaturaDegil     0,00    25,10   0,00    NULL
M01514  2019-02-11  Vadesi Gelmemiş 25,10   0,00    25,10   NULL

我也使用了以下代码(FNM00_ACC_CODE 是 ACCID),得到了几乎正确的结果。

select FNM00_ACC_CODE,borc,alacak,BAKIYE,bdate,vadekontrol,
(cast(((SELECT TOP 1 BAKIYE FROM GRID_Temp_Current_Accounts_All_Can2 ac2 
WHERE ac2.FNM00_ACC_CODE=c.FNM00_ACC_CODE ORDER BY ac2.ID desc)-
            (select ISNULL(sum(convert(decimal(18,2),BORC)),'0.00') as money 
from GRID_Temp_Current_Accounts_All_Can2 as ac
        WHERE ac.FNM00_ACC_CODE=c.FNM00_ACC_CODE
            and ac.id >= c.id)) as money)) BAKIYE2 from 
GridTelekom_MetaData.dbo.GRID_Temp_Current_Accounts_All_Can2 c




  FNM00_ACC_CODE      borc     alacak        BAKIYE    bdate    vadekontrol BAKIYE2
          M00385      2228,75   0,00     7689,75    2018-11-19  Vadesi Geçmiş   -7039,00
          M00385      2545,34   0,00     10235,09   2018-11-29  Vadesi Geçmiş   -4810,25
          M00385      2256,00   0,00     12491,09   2018-12-18  Vadesi Geçmiş   -2264,91
          M00385      0,00     3000,00   9491,09    2018-12-20  FaturaDegil -8,91
          M00385      0,00     3500,00   5991,09    2018-12-28  FaturaDegil -8,91
          M00385      2969,42   0,00     8960,51    2018-12-31  Vadesi Geçmiş   -8,91
          M00385      2244,15   0,00     11204,66   2019-01-18  Vadesi Geçmiş   2960,51  
          M00385      0,00     6000,00   5204,66    2019-01-24  FaturaDegil 5204,66
          M00385      2237,34   0,00     7442,00    2019-01-29  Vadesi Geçmiş   5204,66
          M00385      2217,11   0,00     9659,11    2019-02-18  Vadesi Gelmemiş 7442,00

每当 BAKIYE2 达到负值时,我希望交易上升并包括到那个点。因此,对于上面的示例,我需要最后 5 行,因为最后 5 行的 BORC 总和等于 9668.02,这比最后一个当前 BAKIYE(即 9659.11)多 8.91。然后,我可以区分到期的到期日和未到期的到期日。

虽然我在考虑使用这种方法选择 BAKIYE2 >= 0 的所有条目,但这会跳过将 BAKIYE 变为负数的最后一行(在这种情况下,它不会选择 2969.42)。

【问题讨论】:

【参考方案1】:

我已更改查询以提供 1 个新列,并对先前提供的原始计算列进行更改。

我还翻译了一些列名,以便于我使用它们(如果给您带来不便,我深表歉意)。

此查询现在通过从当时的余额 (bakiye) 中扣除债务 (borc) 的总和来显示余额何时达到 0。它还显示任何到期发票,是否有未清余额需要支付,包括任何信用 (alacak)。这是使用您使用的相关内联子查询完成的,但使用 bdate 而不是 accid 来建立最新余额并在达到 0 或更少之前查询记录,而不是在达到 0 或更少之后查询记录,这是您的版本中发生的情况查询。

我希望这很有用,如果我们更接近或是否有进一步的调整,请告诉我。

declare @t table (
ACCID nvarchar(10),
BDATE date,
MaturityControl nvarchar(15),
Debt float,
Credit float,
Balance float
);

insert into @t (ACCID, BDATE, MaturityControl, Debt, Credit, Balance)
values
('M01518',  '2018-12-12',  'expired',         64.51,     0.00,   64.51),
('M01518',  '2019-01-14',  'expired',         69.00,     0.00,  133.51),
('M01518',  '2019-02-12',  'not expired',     69.00,     0.00,  202.51),
('M01518',  '2019-02-18',  'not invoice',      0.00,   203.00,   -0.49),
('M01517',  '2018-12-14',  'expired',         93.49,     0.00,   93.49),
('M01517',  '2019-01-14',  'expired',         93.49,     0.00,  186.98),
('M01517',  '2019-02-12',  'not expired',     93.49,     0.00,  280.47),
('M01516',  '2018-12-25',  'expired',         982.81,    0.00,  982.81),
('M01516',  '2019-01-21',  'expired',         999.59,    0.00,  1982.40),
('M01514',  '2018-12-11',  'expired',          25.10,    0.00,    25.10),
('M01514',  '2019-01-10',  'not invoice',       0.00,   25.10,     0.00),
('M01514',  '2019-01-14',  'expired',          25.10,    0.00,    25.10),
('M01514',  '2019-01-24',  'not invoice',       0.00,   25.10,     0.00),
('M01514', ' 2019-02-11',  'not expired',      25.10,    0.00,    25.10),
('M00385',  '2018-11-19', 'expired',           2228.75, 0.00, 7689.75),
('M00385', '2018-11-29', 'expired',            2545.34, 0.00, 10235.09),
('M00385', '2018-12-18', 'expired',            2256.00, 0.00, 12491.09),
('M00385', ' 2018-12-20', 'not invoice',       0.00, 3000.00, 9491.09),
('M00385', '2018-12-28', 'not invoice',        0.00, 3500.00, 5991.09),
('M00385', '2018-12-31', 'expired',            2969.42, 0.00, 8960.51),
('M00385', '2019-01-18', 'expired',            2244.15, 0.00, 11204.66),
('M00385', '2019-01-24', 'not invoice',        0.00, 6000.00, 5204.66),
('M00385', '2019-01-29', 'expired',            2237.34, 0.00, 7442.00),
('M00385', '2019-02-18', 'not expired',        2217.11, 0.00, 9659.11);

select t.ACCID, t.BDATE, MaturityControl, Debt, Credit, Balance, 
case when Balance_Less_Debt is null then balance-debt else Balance_Less_Debt end as computed_difference_in_transactions,
(select((select top 1 Balance from @t as t4 where t.accid=t4.ACCID order by t4.BDATE desc)-
(select sum(Debt) from @t as t3 where t.ACCID=t3.ACCID and t.BDATE>=t3.BDATE))-
(select sum(Credit) from @t as t5 where t.ACCID=t5.ACCID and t.BDATE>=t5.BDATE)) as current_balance_less_summed_debt
from @t as t
outer apply (select ACCID, BDATE, Balance-Debt as Balance_Less_Debt from @t t2 where 
t.ACCID=t2.ACCID and t.BDATE=t2.BDATE and MaturityControl='expired'
group by ACCID, BDATE, Balance, Debt
having balance-Debt <=0
) 
agg 
where MaturityControl = 'expired'
order by t.ACCID desc, t.BDATE;

【讨论】:

首先感谢代码。但是,当 bakiye less borc 等于或小于 0 时,这不会停止。我还稍微编辑了这个问题,因为这是一个会计记录,我们有不同的总余额 (Bakiye),因为我们忽略了未过期的值这也弥补了余额。请记住,如果 BORC 值为 0,则交易为信用,如果 ALACAK 值为 0,则交易为债务。因此,为了从最后一个开始找到当前余额,我们可能必须从 BAKIYE 中减去 BORC 和 ALACAK 值。 您能否为您的一个客户群提供示例输出?这将帮助我想象你在寻找什么。我觉得我们已经接近答案了。 用输出和预期输出编辑了原始帖子。 您提供的最新代码几乎可以运行 Dwight,它只需要从最后一个日期开始减去总债务,而不是从第一个日期开始。我在哪里可以更改它,玩过 desc 和 asc 但无法管理它? 在尝试了不同的东西之后,我终于解决了使用公用表表达式的问题。感谢 Dwight 的帮助,我意识到可以通过更简单的查询来解决问题,并且在测试了一堆数据之后,它似乎是正确的。我错误地表述了这个问题,这很糟糕。再次感谢。

以上是关于SQL Server:对列的每个组值求和(或差),直到在另一列上满足条件的主要内容,如果未能解决你的问题,请参考以下文章

mysql 行转列,对列的分组求和,对行求和

使用 Linux 工具根据另一列的 id 对列的值求和

使用子查询对列的值求和

SonataAdminBundle 如何在列表视图中对列的值求和

如何聚合数据框并通过 r 中的重复行对列的值求和

有没有办法在oracle sql developer中对列的每个字段执行md5散列,并将结果散列存储在相应的列中(md5)