SQL 服务器:对列的每个组值求和(或求差),直到满足另一列的条件
SQL Server : summing (or difference) each group values of a column until a condition is met on another column
我对 SQL 和使用 SQL Server 2012 还很陌生。我在下面使用的数据集中有一个示例。它是银行交易和发票金额的会计数据集,具有以下值客户 ID、发票日期、VADEKONTROL 指示发票到期是否过期-未过期-不是发票,BORC 是发票金额,ALACAK 是收到的付款金额, BAKIYE 是总余额。不是发票交易是银行收据。
我想为每个客户做的是从 BAKIYE 的最后数量中减去 BORC 列中从最后一个条目开始的值,直到差异 <= 0。如果没有更多条目,它应该停止减去找到的分组客户。因此,对于 M01516,应该从 1982,40 中减去 999,59,并且由于差值不为 0,继续减去 982,81 和进一步的结果(如果有的话),直到差值 <= 0。
如果某个客户的 BAKIYE 最后一个值等于 0,也不需要减法。
基本逻辑如上:
我想 select 从 BAKIYE 中减去的条目(直到 BAKIYE 达到 0 或 selected 条目与 bakiye 的总和之差达到 0,无论哪种方式你看看。
对最有可能使用分组依据的每个客户的 selected 条目进行计数和求和。
编辑:
请记住,如果 BORC 值为 0,则交易为信用,如果 ALACAK 值为 0,则交易为债务。因此,为了从上一个开始找到当前余额,我们可能必须从 BAKIYE 中减去 BORC 和 ALACAK 值。
基本上我想要的是从最后一条记录开始的每个客户组:获取 BAKIYE 值的最后一行,从同一行的 BAKIYE 中减去 BORC+ALACAK。重复这一行,直到每个客户的 BAKIYE <= 0。有了这个,我可以 select 发票金额和发票数量来支付客户的余额。
我该如何继续解决这个问题?
如有任何帮助,我们将不胜感激。
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 代码的 edit2 输出:
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,比我 9659.11 的最后一个当前 BAKIYE 多 8.91。然后我可以区分过期和未过期的到期日。
使用这种方法,虽然我正在考虑 selecting 所有 BAKIYE2 >= 0 的条目,但是这将跳过最后一行,它将 BAKIYE 带入负数(在这种情况下它不会 select 2969.42).
我已更改查询以提供 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;
我对 SQL 和使用 SQL Server 2012 还很陌生。我在下面使用的数据集中有一个示例。它是银行交易和发票金额的会计数据集,具有以下值客户 ID、发票日期、VADEKONTROL 指示发票到期是否过期-未过期-不是发票,BORC 是发票金额,ALACAK 是收到的付款金额, BAKIYE 是总余额。不是发票交易是银行收据。
我想为每个客户做的是从 BAKIYE 的最后数量中减去 BORC 列中从最后一个条目开始的值,直到差异 <= 0。如果没有更多条目,它应该停止减去找到的分组客户。因此,对于 M01516,应该从 1982,40 中减去 999,59,并且由于差值不为 0,继续减去 982,81 和进一步的结果(如果有的话),直到差值 <= 0。
如果某个客户的 BAKIYE 最后一个值等于 0,也不需要减法。
基本逻辑如上:
我想 select 从 BAKIYE 中减去的条目(直到 BAKIYE 达到 0 或 selected 条目与 bakiye 的总和之差达到 0,无论哪种方式你看看。
对最有可能使用分组依据的每个客户的 selected 条目进行计数和求和。
编辑:
请记住,如果 BORC 值为 0,则交易为信用,如果 ALACAK 值为 0,则交易为债务。因此,为了从上一个开始找到当前余额,我们可能必须从 BAKIYE 中减去 BORC 和 ALACAK 值。
基本上我想要的是从最后一条记录开始的每个客户组:获取 BAKIYE 值的最后一行,从同一行的 BAKIYE 中减去 BORC+ALACAK。重复这一行,直到每个客户的 BAKIYE <= 0。有了这个,我可以 select 发票金额和发票数量来支付客户的余额。
我该如何继续解决这个问题?
如有任何帮助,我们将不胜感激。
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 代码的 edit2 输出:
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,比我 9659.11 的最后一个当前 BAKIYE 多 8.91。然后我可以区分过期和未过期的到期日。
使用这种方法,虽然我正在考虑 selecting 所有 BAKIYE2 >= 0 的条目,但是这将跳过最后一行,它将 BAKIYE 带入负数(在这种情况下它不会 select 2969.42).
我已更改查询以提供 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;