Я работаю с таблицей, в которой содержатся кредитные транзакции, в которой я хочу отобразить, какие кредиты были потрачены при продаже.
В таблице:
Credits
добавляются объектом с использованием уникального кода объекта (записано в столбце GivenByUserCode
)
- Кредитные дополнения всегда имеют такой код.
- Использованные кредиты всегда будут иметь отрицательное значение.
- На использованные кредиты не будет установлен код объекта (значение
GivenByUserCode
равно null
).
Используя приведенные выше данные в качестве примера, если пользователь совершает покупку по 2018-01-02
, в отчете должны быть показаны все эти кредиты, полученные с BM01
. Сложность сложения заключается в том, что покупку можно разделить на несколько дополнений, см. Покупку на 2018-02-03
, которая делится на 3 дополнения.
Я думаю, что решение будет как-то связано с использованием cte и over , но у меня нет опыта их использования. Я нашел похожую (не ту же) проблему на SqlServerCentral .
Любая помощь / направление будет наиболее ценно.
Вход и DDL
DECLARE @CreditLogs TABLE(CreditLogId int not null identity(1,1), Credits INT NOT NULL, OccurredOn DATETIME2(7) NOT NULL, GivenByUserCode VARCHAR(100) NULL)
INSERT INTO @CreditLogs (Credits, OccurredOn, GivenByUserCode) VALUES
(10, '2018-01-01', 'BM01')
, (10, '2018-01-01', 'BM01')
, (-10, '2018-01-02', NULL)
, (-5, '2018-01-04', NULL)
, (5, '2018-02-01', 'SP99')
, (40, '2018-02-02', 'BM02')
, (-40, '2018-02-03', NULL)
, (-4, '2018-03-05', NULL)
Ввод в табличной форме
CreditLogId | Credits | OccurredOn | GivenByUserCode
------------+---------+------------+----------------
1 | 10 | 2018-01-01 | BM01
2 | 10 | 2018-01-01 | BM01
3 | -10 | 2018-01-02 | NULL
4 | -5 | 2018-01-04 | NULL
5 | 5 | 2018-02-01 | SP99
6 | 40 | 2018-02-02 | BM02
7 | -40 | 2018-02-03 | NULL
8 | -4 | 2018-03-05 | NULL
Ожидаемый результат
SELECT *
FROM (VALUES
(3, '2018-01-02', 10, 'BM01')
,(4, '2018-01-04', 5, 'BM01')
,(7, '2018-02-03', 5, 'BM01')
,(7, '2018-02-03', 5, 'SP99')
,(7, '2018-02-03', 30, 'BM02')
,(8, '2018-03-05', 4, 'BM02')
) expectedOut (CreditLogId, OccurredOn, Credits, GivenByUserCode)
Производит продукцию
CreditLogId | Occurred on | Credits | GivenByUserCode
------------+-------------+---------+----------------
3 | 2018-01-02 | 10 | BM01
4 | 2018-01-04 | 5 | BM01
7 | 2018-02-03 | 5 | BM01
7 | 2018-02-03 | 5 | SP99
7 | 2018-02-03 | 30 | BM02
8 | 2018-03-05 | 4 | BM02
Код пока
Это немного, и я не уверен, куда идти.
WITH totals AS (
SELECT CreditLogId, OccurredOn, credits, sum(credits) OVER(ORDER BY OccurredOn) AS TotalSpent
FROM @CreditLogs
WHERE Credits < 0
)
SELECT *
FROM totals
Дополнительные уточнения
Ожидаемый результат - для каждой потраченной суммы кредита, откуда были получены эти кредиты. Кредиты расходуются по принципу «первым пришел - первым вышел» (FIFO). Вот объяснение каждого значения в примере вывода в надежде, что это прояснит желаемый результат.
- Для расходования 10 кредитов (идентификатор кредитного журнала 3) можно проследить до сложения из идентификатора кредитного журнала 1
- Для расходования 5 кредитов (идентификатор кредитного журнала 4) можно проследить до дополнения из идентификатора кредитного журнала 2 (так как идентификатор кредитного журнала 1 был «использован»)
- Для расходования 40 кредитов в кредитном журнале идентификатор 7 можно отследить до
- Остаток добавления из идентификатора кредитного журнала 2, 5 кредитов
- Идентификатор кредитной карты 5 (дополнение 5)
- Идентификатор кредитной истории 6 (добавление 40, так что осталось 10)
- Для расходования 4 кредитов в кредитном журнале 8 используется остаток 6 кредитного журнала
Обратите внимание, что общий баланс составляет 6 кредитов, баланс не нужно обнулять, но он никогда не будет отрицательным, поскольку пользователи могут тратить только то, что имеют.