Запрос на отображение потраченных кредитов из транзакционной таблицы - PullRequest
0 голосов
/ 24 апреля 2018

Я работаю с таблицей, в которой содержатся кредитные транзакции, в которой я хочу отобразить, какие кредиты были потрачены при продаже.

В таблице:

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

Ответы [ 2 ]

0 голосов
/ 27 апреля 2018

попробуйте это:

WITH Credits_added AS (
    SELECT CreditLogId, OccurredOn, credits
    , SUM(credits) OVER (ORDER BY CreditLogId) - credits AS b --before
    , SUM(credits) OVER (ORDER BY CreditLogId) AS a --after
    , GivenByUserCode
    FROM @CreditLogs
    WHERE Credits > 0)
, Credits_spent AS (
    SELECT CreditLogId, OccurredOn, credits
    , SUM(credits) OVER (ORDER BY CreditLogId) * -1 + credits AS b
    , SUM(credits) OVER (ORDER BY CreditLogId) * -1 AS a
    FROM @CreditLogs
    WHERE Credits < 0)
SELECT s.CreditLogId, s.OccurredOn
, CASE WHEN a.a > s.a THEN s.a ELSE a.a END - CASE WHEN a.b > s.b THEN a.b ELSE s.b END AS Credits 
, a.GivenByUserCode
FROM Credits_added AS a
INNER JOIN Credits_spent AS s ON a.a > s.b AND s.a > a.b
0 голосов
/ 27 апреля 2018

, поскольку вы упомянули, что в год будет от 4 до 5 миллионов записей, даже если это можно сделать с помощью запроса, это будет медленный запрос.

Я бы предложил иметь другую таблицу, такую ​​как creditSpent, котораясодержит (PurchaseCreditLogId , additionCreditLogId, Amount)

И во время вставки покупок найдите все записи, рассчитайте сумму, которая должна быть уменьшена с каждой из них, и сохраните эту информацию в этой таблице

Затем, когда вы запускаетесвой отчет вы можете сделать простым запросом по этой таблице

...