Просмотрите каждую строку таблицы, выполните вычисления для этой строки, вставьте в временную таблицу и используйте временную таблицу для следующей строки. - PullRequest
0 голосов
/ 13 января 2019

Проблема:
У нас есть таблица транзакций. Все записи в этой таблице имеют один из следующих типов транзакций: пополнение кошелька (платежи), снятие кошелька (продажа) и возврат наличных (скидка, которая будет использоваться для будущих продаж). Я хочу добавить дополнительный столбец в каждую строку, отображающую остаток кешбека. Кэшбэк используется либо для дисконта при новых продажах, либо для уменьшения отрицательного общего баланса.

таблица транзакций:

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

Поиск в интернете Думаю, мне следует использовать цикл или, возможно, курсор?

Идея:
Идея состоит в том, чтобы использовать таблицу транзакций и добавить два столбца столбцов. Rowumber для всех строк в таблице транзакций, которые я хочу просмотреть. И второе число на все транзакции каждого клиента. Следующим шагом кажется создание пустой таблицы баланса с полями rownumclient, client_id, total_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

таблица транзакций с номерами:

rownumber_all (int)
rownumber_client (int)
client (int)
transaction_date (date)
amount (int)
transaction_type (varchar(25))

таблица баланса:

rownumber_client (int)
client_id (int)
overall_balance (int)
cashback_balance (int)

пример таблицы транзакций с номерами:

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 и новой таблицы баланса мне нужно создать цикл по всем строкам в таблице транзакций. Использование столбца rownumber_all, чтобы начать с первого. Вновь созданная таблица баланса используется для расчета баланса кешбека в текущей строке. Мы используем эту таблицу с левым соединением с таблицей транзакций со столбцами rownumber. Когда мы перебираем первую строку, таблица баланса пуста, но со второй строки вычисляется остаток кешбека из предыдущей строки.

выберите выписку для расчета текущего кэшбэка:

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

Для каждой строки, которая проходит через результат оператора выбора выше, следует вставить в таблицу сальдо, пока есть доступные записи транзакций. И, как уже было сказано, остаток кешбэка либо используется для дисконта при новых продажах, либо для уменьшения отрицательного общего баланса Тем не менее, ожидаемый результат, который я ищу, выглядит следующим образом, а cashback_balance - самое важное поле.

таблица ожидаемых транзакций с остатками:

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 будет достаточно любезен, чтобы сказать мне простым языком, как этого можно добиться, используя цикл, курсор или любой другой способ? Любая помощь будет высоко оценен. Если требуется какое-либо разъяснение, пожалуйста, дайте мне знать.

Ответы [ 2 ]

0 голосов
/ 14 января 2019

После поиска и проб и ошибок я нашел способ перебрать все строки и вычислить правильный баланс кешбека для каждой строки. Я хочу поблагодарить всех людей, которые пытались помочь мне и Хорхе Э. Эрнандесу за решение моей "проблемы петли".

Вот последний код, который я использовал.

-- 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
0 голосов
/ 13 января 2019

Вы ищете промежуточную сумму, такую ​​как выписка из банка. Этот запрос делает это

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

Пример данных

enter image description here

...