Арифметический расчет с использованием предыдущей записи для двух столбцов, которые зависят друг от друга в SQL - PullRequest
3 голосов
/ 24 апреля 2019

В моей таблице я должен рассчитать значения для разных столбцов. Значения могут быть получены из текущей строки и предыдущей строки. Эти два значения столбца зависят друг от друга. Если я изменяю значения одного столбца, это влияет на другой.

Я поделился образцом таблицы для вашей справки

A   | B   | C   | D
500 | 400 | 400 | 0
300 | 400 | 300 | 100
200 | 500 | 200 | 400
700 | 200 | 600 | 0
900 | 800 | 800 | 0

В приведенной выше таблице я должен рассчитать столбцы C и D. Формула Excel:

  • 1-я строка C является IF (A2> B2, B2, A2)
  • 2-я строка до последней строки C - IF (A3> B3 + D2, B3 + D2, A3)
  • 1-й ряд D является IF (A2-B2 <= 0, -1 * (A2-B2), 0) </li>
  • 2-я строка до последней строки D - IF (A3- (B3 + D2) <= 0, -1 * (A3- (B3 + D2)), 0) </li>

Как поступить так же в sql

CREATE TABLE sampl (A int, B int);
INSERT INTO SAMPL VALUES (500, 400);
INSERT INTO SAMPL VALUES (300, 400);
INSERT INTO SAMPL VALUES (200, 500);
INSERT INTO SAMPL VALUES (700, 200);
INSERT INTO SAMPL VALUES (900, 800);
SELECT * FROM sampl
SELECT *, CASE WHEN A>B THEN B ELSE A END C, CASE WHEN A-B<=0 THEN -1*(A-B) ELSE 0 END D FROM sampl

Как поступить на несколько записей

rn  Tab a   b   c   d    
1   AA  500 400 400 0    
2   AA  300 400 300 100    
3   AA  200 500 200 400    
4   AA  700 200 600 0    
5   AA  900 800 800 0    
1   BB  500 400 400 0    
2   BB  300 400 300 100    
3   BB  200 500 200 400   
4   BB  700 200 600 0

1 Ответ

2 голосов
/ 24 апреля 2019

Я перевел формулу в рекурсивный CTE:

DECLARE @tbl TABLE (tab VARCHAR(100), rn INT, a INT, b INT);
INSERT INTO @tbl VALUES
('aa', 1, 500, 400),
('aa', 2, 300, 400),
('aa', 3, 200, 500),
('aa', 4, 700, 200),
('aa', 5, 900, 800),
('bb', 1, 500, 400),
('bb', 2, 300, 400),
('bb', 3, 200, 500),
('bb', 4, 700, 200);

WITH rcte AS (
    SELECT tab
         , rn
         , a
         , b
         , IIF(a > b, b, a) AS c
         , IIF(a - b <= 0, -1 * (a - b), 0) AS d
    FROM @tbl
    WHERE rn = 1

    UNION ALL

    SELECT curr.tab
         , curr.rn
         , curr.a
         , curr.b
         , IIF(curr.a > curr.b + prev.d, curr.b + prev.d, curr.a)
         , IIF(curr.a - (curr.b + prev.d) <= 0, -1 * (curr.a - (curr.b + prev.d)), 0)
    FROM @tbl AS curr
    JOIN rcte AS prev ON curr.tab = prev.tab AND curr.rn = prev.rn + 1
)
SELECT *
FROM rcte
ORDER BY tab, rn

Обратите внимание, что я добавил столбец rn к данным.Вы можете использовать ROW_NUMBER() OVER (PARTITION BY tab ORDER BY foo) для генерации этого столбца, если это необходимо.Также обратите внимание, что a - b <= 0 можно записать как a <= b.

Демо на db <> fiddle

...