Выбирайте строки, пока промежуточная сумма не достигнет определенного значения - PullRequest
0 голосов
/ 11 октября 2018

У меня есть следующие данные:

DECLARE @t TABLE (usr VARCHAR(100), dt DATE, amount INT);
INSERT INTO @t VALUES
('a', '2018-01-01', 100), -- 100
('a', '2018-02-01', 100), -- 200
('a', '2018-03-01', 100), -- 300
('a', '2018-04-01', 100), -- 400
('a', '2018-05-01', 100), -- 500
('b', '2018-01-01', 150), -- 150
('b', '2018-02-01', 150), -- 300
('b', '2018-03-01', 150), -- 450
('b', '2018-04-01', 150), -- 600
('b', '2018-05-01', 150); -- 750

И значение, например 300 или 301 (пользовательская переменная или столбец).Я хочу выбирать строки, пока итоговая сумма не достигнет указанного значения со следующим поворотом:

  • Для 300 Я хочу выбрать первые 3 строки для a и первые 2 строки для b
  • Для 301 я хочу выбрать первые 4 строки для a и первые 3 строки для b

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

Ответы [ 2 ]

0 голосов
/ 11 октября 2018
DECLARE @t TABLE (usr VARCHAR(100), dt DATE, amount INT);
INSERT INTO @t VALUES
('a', '2018-01-01', 100), -- 100
('a', '2018-02-01', 100), -- 200
('a', '2018-03-01', 100), -- 300
('a', '2018-04-01', 100), -- 400
('a', '2018-05-01', 100), -- 500
('b', '2018-01-01', 150), -- 150
('b', '2018-02-01', 150), -- 300
('b', '2018-03-01', 150), -- 450
('b', '2018-04-01', 150), -- 600
('b', '2018-05-01', 150); -- 750

declare @target int = 300;

with cte_RunningTotal as
(
    select  
        usr,
        dt,
        amount,
        sum(amount) over (partition by usr order by dt rows unbounded preceding) as runningTotal
    from @t 
)
select *
from cte_RunningTotal 
where runningTotal < @target + amount
order by usr, dt
0 голосов
/ 11 октября 2018
DECLARE @t TABLE (usr VARCHAR(100), dt DATE, amount INT);
INSERT INTO @t VALUES
('a', '2018-01-01', 100), -- 100
('a', '2018-02-01', 100), -- 200
('a', '2018-03-01', 100), -- 300
('a', '2018-04-01', 100), -- 400
('a', '2018-05-01', 100), -- 500
('b', '2018-01-01', 150), -- 150
('b', '2018-02-01', 150), -- 300
('b', '2018-03-01', 150), -- 450
('b', '2018-04-01', 150), -- 600
('b', '2018-05-01', 150); -- 750

DECLARE @Total INT = 301;

WITH cte AS
(
    SELECT *, SUM(amount) OVER (PARTITION BY usr ORDER BY dt) AS RunTotal
    FROM @t
)
SELECT *
FROM   cte
WHERE  cte.RunTotal - cte.amount < @Total -- running total for previous row is less
                                          -- than @Total then include current row
...