遍历 a table 的每一行,对该行进行计算,插入 temp table 并将 temp table 用于下一行
Go through each row of a table, do a calculation on that row, insert in temp table and use temp table for next row
问题:
我们有一笔交易 table。 table 中的所有记录都具有以下交易类型之一:钱包存款(付款)、钱包提款(销售)和现金返还(用于未来销售的折扣)。我想在显示现金返还余额的每一行中添加一个额外的列。现金返还用于新销售的折扣或减少负的整体余额。
交易table:
customer (int)
transaction_date (date)
amount (int)
transaction_type (varchar(25))
我试过使用滞后函数获取上一行的值并将其用于当前行的计算。但这并不总是有效,因为滞后函数会回顾它特别指向的行。
在计算中使用滞后函数:
case when
isnull(lag(balance_cashback) over (partition by client_id order by transaction_date), 0)
+ case when type = "cashback" then amount else 0 end
+ case when type = "revenu" and amount < 0 then amount else 0 end
<= 0 then 0
else
lag(balance_cashback) over (partition by client_id order by transaction_date)
+ case when type = "cashback" then amount else 0 end
+ case when type = "revenu" and amount < 0 then amount else 0 end
end
在互联网上搜索我认为我应该使用循环或游标?
想法:
这个想法是使用事务 table 并添加两个 rownumber 列。事务中所有行的行号 table 我要循环。每个客户的所有交易都有第二个行号。下一步似乎是用字段 rownumclient、client_id、overall_balance 和 cashback_balance.
创建一个空余额 table
行数列的计算:
row_number () over (order by client_id, transaction_date) as rownumber_all
row_number () over (partition by client_id order by client_id, transaction_date) as rownumber_client
事务 table 行号:
rownumber_all (int)
rownumber_client (int)
client (int)
transaction_date (date)
amount (int)
transaction_type (varchar(25))
余额table:
rownumber_client (int)
client_id (int)
overall_balance (int)
cashback_balance (int)
示例交易 table 行号:
rownumbwr_all | rownumber_client | client_id | transaction_date | amount | transaction_type
1 1 123 2018-10-12 10 wallet deposit
2 2 123 2018-10-27 5 cashback
3 3 123 2018-11-03 -2,5 wallet withdrawal
4 4 123 2018-11-13 -5 wallet withdrawal
5 5 123 2018-12-18 10 wallet deposit
6 6 123 2018-12-19 20 wallet deposit
7 7 123 2018-12-21 5 cashback
8 1 456 2018-10-11 -45 wallet withdrawal
9 2 456 2018-10-23 5 cashback
10 3 456 2018-11-01 5 cashback
11 4 456 2018-11-04 10 wallet deposit
Etc.
有了额外的 rownumber 列和新的余额 table,我必须创建一个遍历事务 table 中所有行的循环。使用列 rownumber_all 从第一个开始。新创建的余额table用于计算当前行的返现余额。我们将此 table 与带有行号列的事务表的左连接一起使用。当我们遍历第一行时,余额 table 是空的,但是从第二行开始,就会有上一行计算出的现金返还余额。
select计算当前返现余额的语句:
select
t1.rownumall,
t1.rownumclient,
t1.client_id,
t2.overall_balance + t1.amount as overall_balance,
case
when (t2.overall_balance + case when t1.type = 'cashback' then t1.amount else 0 end) < 0 then 0
when t1.type in (sales, cashback) then amount
else null
end + t2.cashback_balance as cashback_balance
/*insert into balance*/
from
transactions as t1
left join cashback as t2 on t2.client_id = t1.client_id and t2.rownumber_client = t1.rownumber_client-1
只要有可用的交易记录,就应将上述 select 语句结果循环的每一行插入到余额 table 中。正如之前所说,现金返还余额要么用于新销售的折扣,要么用于减少负的整体余额。也就是说,我正在寻找的预期结果如下,cashback_balance 是最重要的字段。
预期交易 table 余额:
client_id | transaction_date | amount | transaction_type | overall_balance | cashback balance
123 2018-10-12 10 wallet deposit 10 0
123 2018-10-27 5 cashback 15 5
123 2018-11-03 -2,5 wallet withdrawal 12,5 2,5
123 2018-11-13 -5 wallet withdrawal 7,5 0
123 2018-12-18 10 wallet deposit 17,5 0
123 2018-12-19 20 wallet deposit 37,5 0
123 2018-12-21 5 cashback 42,5 5
456 2018-10-11 -45 wallet withdrawal -2,5 0
456 2018-10-23 5 cashback 2,5 2,5
456 2018-11-01 5 cashback 7,5 7,5
456 2018-11-04 10 wallet deposit 17,5 7,5
Etc.
我尽量解释清楚,希望思路和预期结果是清楚的。我无法想象我需要的东西以前没有做过,但我似乎无法在任何地方找到具体的用例。
哪位 SQL 专家会用简单的英语告诉我如何使用循环、游标或任何其他方式实现这一点?任何帮助将不胜感激。如果需要任何说明,请告诉我。
您是否在寻找 运行 总额,如银行对帐单。这个查询就是这样做的
SELECT
client_id,
Transaction_Date,
Trans_Type,
Amount,
Balance = SUM(CASE WHEN Trans_Type = 'Cash back' Then Amount ELSE 0 END) OVER(ORDER BY RowNumber)
FROM
(
SELECT
client_id,
Transaction_Date,
Trans_Type,
Amount,
ROW_NUMBER() OVER(ORDER BY Client_id) AS RowN
FROM temp.dbo.Trans_Table) RC
GROUP BY client_id, Trans_Type, Transaction_Date, Amount, RowN
示例数据
经过搜索和反复试验后,我找到了一种遍历所有行并为每一行计算正确现金返还余额的方法。我要感谢所有试图帮助我的人和 Jorge E. Hernández for the solution 我的 "loop problem"。
这是我使用的最终代码。
-- declare the start and end variable
declare
@counter int = 1,
@max_rownumber int = (select max(rownumber_all) as max_rownumber from dbo.transactions)
-- loop
while @counter <= @max_rownumber
begin
-- calculate overall_balance and cashback_balance for each row in the transactions table filtered by the rownumber_all field
insert into dbo.transactions_enriched
select
t1.rownumber_client as rownumber
, t1.client_id
, t1.transaction_date
, t1.amount
, t1.transaction_type
, t1.payment_method
, isnull(t2.overall_balance ,0) + t1.amount as overall_balance
, case
when t1.transaction_type = 'cashback' and isnull(t2.overall_balance, 0) >= 0 then isnull(t2.cashback_balance, 0) + t1.amount
when (case when t1.transaction_type = 'revenue' and t1.amount < 0 then t1.amount else 0 end) + isnull(t2.cashback_balance, 0) <= 0 then 0
else (case when t1.transaction_type = 'revenue' and t1.amount < 0 then t1.amount else 0 end) + isnull(t2.cashback_balance, 0)
end as cashback_balance
from
dbo.transactions as t1
left join dbo.transactions_enriched as t2 on t2.client_id = t1.client_id and t2.rownumber_client = t1.rownumber_client - 1
where
t1.rownumber_all = @counter
-- update the counter by adding 1
set @counter = @counter + 1
end
问题:
我们有一笔交易 table。 table 中的所有记录都具有以下交易类型之一:钱包存款(付款)、钱包提款(销售)和现金返还(用于未来销售的折扣)。我想在显示现金返还余额的每一行中添加一个额外的列。现金返还用于新销售的折扣或减少负的整体余额。
交易table:
customer (int)
transaction_date (date)
amount (int)
transaction_type (varchar(25))
我试过使用滞后函数获取上一行的值并将其用于当前行的计算。但这并不总是有效,因为滞后函数会回顾它特别指向的行。
在计算中使用滞后函数:
case when
isnull(lag(balance_cashback) over (partition by client_id order by transaction_date), 0)
+ case when type = "cashback" then amount else 0 end
+ case when type = "revenu" and amount < 0 then amount else 0 end
<= 0 then 0
else
lag(balance_cashback) over (partition by client_id order by transaction_date)
+ case when type = "cashback" then amount else 0 end
+ case when type = "revenu" and amount < 0 then amount else 0 end
end
在互联网上搜索我认为我应该使用循环或游标?
想法:
这个想法是使用事务 table 并添加两个 rownumber 列。事务中所有行的行号 table 我要循环。每个客户的所有交易都有第二个行号。下一步似乎是用字段 rownumclient、client_id、overall_balance 和 cashback_balance.
行数列的计算:
row_number () over (order by client_id, transaction_date) as rownumber_all
row_number () over (partition by client_id order by client_id, transaction_date) as rownumber_client
事务 table 行号:
rownumber_all (int)
rownumber_client (int)
client (int)
transaction_date (date)
amount (int)
transaction_type (varchar(25))
余额table:
rownumber_client (int)
client_id (int)
overall_balance (int)
cashback_balance (int)
示例交易 table 行号:
rownumbwr_all | rownumber_client | client_id | transaction_date | amount | transaction_type
1 1 123 2018-10-12 10 wallet deposit
2 2 123 2018-10-27 5 cashback
3 3 123 2018-11-03 -2,5 wallet withdrawal
4 4 123 2018-11-13 -5 wallet withdrawal
5 5 123 2018-12-18 10 wallet deposit
6 6 123 2018-12-19 20 wallet deposit
7 7 123 2018-12-21 5 cashback
8 1 456 2018-10-11 -45 wallet withdrawal
9 2 456 2018-10-23 5 cashback
10 3 456 2018-11-01 5 cashback
11 4 456 2018-11-04 10 wallet deposit
Etc.
有了额外的 rownumber 列和新的余额 table,我必须创建一个遍历事务 table 中所有行的循环。使用列 rownumber_all 从第一个开始。新创建的余额table用于计算当前行的返现余额。我们将此 table 与带有行号列的事务表的左连接一起使用。当我们遍历第一行时,余额 table 是空的,但是从第二行开始,就会有上一行计算出的现金返还余额。
select计算当前返现余额的语句:
select
t1.rownumall,
t1.rownumclient,
t1.client_id,
t2.overall_balance + t1.amount as overall_balance,
case
when (t2.overall_balance + case when t1.type = 'cashback' then t1.amount else 0 end) < 0 then 0
when t1.type in (sales, cashback) then amount
else null
end + t2.cashback_balance as cashback_balance
/*insert into balance*/
from
transactions as t1
left join cashback as t2 on t2.client_id = t1.client_id and t2.rownumber_client = t1.rownumber_client-1
只要有可用的交易记录,就应将上述 select 语句结果循环的每一行插入到余额 table 中。正如之前所说,现金返还余额要么用于新销售的折扣,要么用于减少负的整体余额。也就是说,我正在寻找的预期结果如下,cashback_balance 是最重要的字段。
预期交易 table 余额:
client_id | transaction_date | amount | transaction_type | overall_balance | cashback balance
123 2018-10-12 10 wallet deposit 10 0
123 2018-10-27 5 cashback 15 5
123 2018-11-03 -2,5 wallet withdrawal 12,5 2,5
123 2018-11-13 -5 wallet withdrawal 7,5 0
123 2018-12-18 10 wallet deposit 17,5 0
123 2018-12-19 20 wallet deposit 37,5 0
123 2018-12-21 5 cashback 42,5 5
456 2018-10-11 -45 wallet withdrawal -2,5 0
456 2018-10-23 5 cashback 2,5 2,5
456 2018-11-01 5 cashback 7,5 7,5
456 2018-11-04 10 wallet deposit 17,5 7,5
Etc.
我尽量解释清楚,希望思路和预期结果是清楚的。我无法想象我需要的东西以前没有做过,但我似乎无法在任何地方找到具体的用例。
哪位 SQL 专家会用简单的英语告诉我如何使用循环、游标或任何其他方式实现这一点?任何帮助将不胜感激。如果需要任何说明,请告诉我。
您是否在寻找 运行 总额,如银行对帐单。这个查询就是这样做的
SELECT
client_id,
Transaction_Date,
Trans_Type,
Amount,
Balance = SUM(CASE WHEN Trans_Type = 'Cash back' Then Amount ELSE 0 END) OVER(ORDER BY RowNumber)
FROM
(
SELECT
client_id,
Transaction_Date,
Trans_Type,
Amount,
ROW_NUMBER() OVER(ORDER BY Client_id) AS RowN
FROM temp.dbo.Trans_Table) RC
GROUP BY client_id, Trans_Type, Transaction_Date, Amount, RowN
示例数据
经过搜索和反复试验后,我找到了一种遍历所有行并为每一行计算正确现金返还余额的方法。我要感谢所有试图帮助我的人和 Jorge E. Hernández for the solution 我的 "loop problem"。
这是我使用的最终代码。
-- declare the start and end variable
declare
@counter int = 1,
@max_rownumber int = (select max(rownumber_all) as max_rownumber from dbo.transactions)
-- loop
while @counter <= @max_rownumber
begin
-- calculate overall_balance and cashback_balance for each row in the transactions table filtered by the rownumber_all field
insert into dbo.transactions_enriched
select
t1.rownumber_client as rownumber
, t1.client_id
, t1.transaction_date
, t1.amount
, t1.transaction_type
, t1.payment_method
, isnull(t2.overall_balance ,0) + t1.amount as overall_balance
, case
when t1.transaction_type = 'cashback' and isnull(t2.overall_balance, 0) >= 0 then isnull(t2.cashback_balance, 0) + t1.amount
when (case when t1.transaction_type = 'revenue' and t1.amount < 0 then t1.amount else 0 end) + isnull(t2.cashback_balance, 0) <= 0 then 0
else (case when t1.transaction_type = 'revenue' and t1.amount < 0 then t1.amount else 0 end) + isnull(t2.cashback_balance, 0)
end as cashback_balance
from
dbo.transactions as t1
left join dbo.transactions_enriched as t2 on t2.client_id = t1.client_id and t2.rownumber_client = t1.rownumber_client - 1
where
t1.rownumber_all = @counter
-- update the counter by adding 1
set @counter = @counter + 1
end