SQL-запрос, внешнее соединение, cte?Нужно исправить итоговую сумму с "левым" значением - PullRequest
0 голосов
/ 09 октября 2018

Я пытаюсь исправить этот запрос в течение нескольких дней.В основном, в каждой группе acount_no и group, необходимо вычесть только сумму, которая меньше максимальной группы .

По сути, если учетная запись 104 имеет максимальную группу 99, и первая сумма равна 75, для этого взято будет равно 75 и оставлено сверх суммы будет 24, затемдля следующей группы B, даже если необходимое количество составляет 64, поскольку осталось только 24, группе B будет дано только 24, а после этого ничего не останется, поэтому группе D останется значение 0.

В основноммоя таблица может иметь такие значения

DECLARE @table AS TABLE(acc_no INT, [group] CHAR(1), [maxgroup] INT, amount INT)

INSERT INTO @table VALUES
(101, 'A', 70, 0),
(101, 'B', 70, 50),
(101, 'C', 70, 0),
(101, 'D', 70, 20),
(102, 'A', 95, 30),
(102, 'B', 95, 0),
(102, 'C', 95, 5),
(102, 'D', 95, 10),
(103, 'A', 80, 40),
(103, 'B', 80,15),
(103, 'C', 80, 10),
(103, 'D', 80, 5),
(104, 'A', 99.53, 75),
(104, 'B', 99.53,64),
(104, 'D', 99.53, 0.53),

(105, 'A', 21.5, 75),
(105, 'D', 21.5,6)



SELECT t.acc_no, 
    t.[group],
    t.maxgroup,t.amount,
    CASE WHEN t1.assigned = 0 THEN NULL ELSE t.amount END AS taken, 
    CASE WHEN t1.assigned = 0 THEN NULL ELSE (t.maxgroup - t1.assigned) END [left]
FROM @table t
OUTER APPLY(SELECT SUM([amount]) AS assigned 
            FROM @table t1 WHERE t1.acc_no = t.acc_no AND t1.[group] <= t.[group]) t1

Это то, что я ожидаю в результате:

 acc_no group   maxgroup    amount  taken   left
101 A   70      0   NULL    NULL
101 B   70      50  50  20
101 C   70      0   0   20
101 D   70      20  20  0
102 A   95      30  30  65
102 B   95      0   0   65
102 C   95      5   5   60
102 D   95      10  10  50
103 A   80      40  40  40
103 B   80      15  15  25
103 C   80      10  10  15
103 D   80      5   5   10
104 A   99      75  75  24
104 B   99      64  24  0    --<<
104 D   99      0   0   0
105 A   21      75  21  0
105 D   21      6   0   0

К сожалению, мой запрос дает отрицательные значения для столбца left для acc_no=104.

Ответы [ 2 ]

0 голосов
/ 09 октября 2018

Чтобы сохранить логику запроса, вы можете отслеживать общее количество предыдущих строк для каждой группы, например:

SELECT t.acc_no, 
    t.[group],
    t.maxgroup, t.amount, 
    CASE WHEN A.previous_assigned + t.amount <= t.maxgroup THEN t.amount
    ELSE CASE When (t.maxgroup - A.previous_assigned) > 0 Then (t.maxgroup - A.previous_assigned)
        ELSE 0
        END 
    END AS taken, 
    CASE WHEN  (t.maxgroup - A.previous_assigned - t.amount) <= 0 THEN 0 
    ELSE (t.maxgroup - A.previous_assigned - t.amount) 
    END AS [left]
FROM @table t
OUTER APPLY(SELECT SUM([amount]) AS assigned, (SUM([amount]) - t.amount) AS previous_assigned
            FROM @table t1 WHERE t1.acc_no = t.acc_no AND t1.[group] <= t.[group]) As A;
0 голосов
/ 09 октября 2018

Вы были очень близки:

CASE 
  WHEN t1.assigned = 0 THEN NULL 
  WHEN t.maxgroup < t1.assigned THEN 0 --<< that's it
  ELSE (t.maxgroup - t1.assigned) 
END [left]

Но я предлагаю следующее:

SELECT t.acc_no, 
    t.[group],
    t.maxgroup,
    t.amount,
    CASE 
      WHEN t.amount = 0 THEN 0
      WHEN t.maxgroup < (t.running_total-t.amount) THEN 0
      WHEN t.maxgroup < t.running_total THEN t.amount - (t.running_total - t.maxgroup)
      ELSE t.amount
    END taken,
    CASE 
      WHEN t.maxgroup < t.running_total THEN 0
      ELSE t.maxgroup - t.running_total
    END [left]
FROM (
  SELECT t.acc_no, 
      t.[group],
      t.maxgroup,
      t.amount,
      SUM(t.amount) OVER(PARTITION BY t.[acc_no] ORDER BY t.[group] ROWS UNBOUNDED PRECEDING) running_total
  FROM stock t
) t
order by 1, 2

Этот будет выполнять только одно сканирование исходной таблицы.Вместо множества циклов с подходом подзапроса.

http://sqlfiddle.com/#!18/ce2f5/12

...