Рассчитать периодические значения из года в день цифры в SQL - PullRequest
0 голосов
/ 17 сентября 2018

Я накопил текущие значения за каждый период. Но мне нужны периодические значения для каждой группы продуктов / периода.

Знаете ли вы решение в SQL Server для простого достижения этой цели?

Это мои образцы данных:

Product Group | Period | Amount
-------------------------------
Group 1       |2018/01 | 500
Group 1       |2018/02 | 740
Group 1       |2018/03 | 900
Group 1       |2018/04 | 930

И результат должен выглядеть так:

Product Group | Period | Amount
-------------------------------
Group 1       |2018/01 | 500
Group 1       |2018/02 | 240
Group 1       |2018/03 | 160
Group 1       |2018/04 | 30

Спасибо за вашу помощь! Philipp

Ответы [ 6 ]

0 голосов
/ 17 сентября 2018

Я бы использовал lag() функцию:

select [Product Group], Period,  
       Amount - LAG(Amount, 1,0) OVER (ORDER BY Period) AS Amount
from table t'

Если у вас более старая версия SQL, вы также можете использовать apply:

select t.product, t.period, coalesce(t.amount-t1.amount, t.amount) as amount
from table t outer apply
     ( select top (1) t1.*
       from table t1
       where t1.product = t.product and 
             t1.period < t.period
             order by t1.period desc
     ) t1;
0 голосов
/ 17 сентября 2018

Если предположить, что вы не можете использовать LAG (например, MSSQL 2008), и что у вас может быть несколько записей для каждой группы продуктов и периода, вы можете использовать следующий запрос.

Пример таблицы и значения:

CREATE TABLE GR (Product_Group VARCHAR(10), Period VARCHAR(6), Amount INT);

INSERT INTO GR VALUES ('Group 1',  '201801', 500)
, ('Group 1',  '201802', 740)
,('Group 1',  '201803', 900)
,('Group 1',  '201804', 930)
;
INSERT INTO GR VALUES ('Group 2',  '201801', 500)
, ('Group 2',  '201803', 800)
,('Group 2',  '201803', 1000)
,('Group 2',  '201804', 1200)
;

Запрос использует GROUP BY (и CTE для упрощения чтения) для группировки по ProductGroup и Period, а RowNumber для поиска предыдущего значения (если у вас фиксированный период, т.е. если вы хотите показать запись для каждого месяца, когда значение месяца отсутствует Вы можете использовать таблицу Tally Date)

WITH X AS (SELECT  Product_Group, Period, SUM(Amount) AS Amount_TOT
            , ROW_NUMBER() OVER (PARTITION BY Product_Group ORDER BY PERIOD) AS RN
            FROM GR GROUP BY Product_group, Period)  
SELECT Product_Group, Period, Amount_TOT,  Amount_TOT_PREC, Amount_TOT-ISNULL(Amount_TOT_PREC,0) AS Delta 
FROM (SELECT  A.Product_Group, A.Period, A.Amount_TOT, B.Amount_TOT AS Amount_TOT_PREC       
        FROM X A
        LEFT JOIN X B ON A.Product_Group=B.Product_Group AND A.RN-1 = B.RN
        ) C 

выход

+---------------+--------+------------+-----------------+-------+
| Product_Group | Period | Amount_TOT | Amount_TOT_PREC | Delta |
+---------------+--------+------------+-----------------+-------+
| Group 1       | 201801 |        500 | NULL            |   500 |
| Group 1       | 201802 |        740 | 500             |   240 |
| Group 1       | 201803 |        900 | 740             |   160 |
| Group 1       | 201804 |        930 | 900             |    30 |
| Group 2       | 201801 |        500 | NULL            |   500 |
| Group 2       | 201803 |       1800 | 500             |  1300 |
| Group 2       | 201804 |       1200 | 1800            |  -600 |
+---------------+--------+------------+-----------------+-------+

Использование LAG (эта функция возвращает значение предыдущей записи, пожалуйста, проверьте документацию Microsoft) быстрее и более читабельно:

WITH X AS (SELECT Product_Group, Period
                  , SUM(Amount) AS Amount_TOT           
            FROM GR GROUP BY Product_group, Period)  
SELECT Product_Group, Period, Amount_TOT, AMOUNT_PREC
       , Amount_TOT-ISNULL(AMOUNT_PREC,0) AS Delta 
FROM (SELECT  Product_Group, Period, Amount_TOT 
              , LAG(Amount_TOT) OVER (PARTITION BY Product_Group 
                 ORDER BY PERIOD) AS AMOUNT_PREC     
        FROM X) A;

То же, что и выше

0 голосов
/ 17 сентября 2018

Надеюсь, это поможет вам.

WITH CTE AS (
SELECT
rownum = ROW_NUMBER() OVER (ORDER BY t.[Product Group],t.[Period]),
t.*
FROM YourTbl AS t
)

SELECT CTE.[Product Group],CTE.Period,-1*(ISNULL(prev.Amount,0)-CTE.Amount) AS Amount 
FROM CTE
LEFT JOIN CTE prev ON prev.rownum = CTE.rownum - 1
0 голосов
/ 17 сентября 2018

Небольшое изменение в запросе

SELECT [ProductGroup], Period,  
      Amount- LAG(Amount, 1,0) OVER (ORDER BY Period)   AS Amount
FROM tablename
0 голосов
/ 17 сентября 2018

Надеюсь, это поможет:

Select 
ProductGroup, 
Period, 
Amount = Amount-ISNULL((Select Amount from TempTable where Period = (select max(Period) from TempTable where Period < Main.Period)),0)
From TempTable Main
Order by Period

Я предположил, что Period - это тип datetime (2018-01-01)

0 голосов
/ 17 сентября 2018

Вы можете использовать функцию LAG следующим образом:

SELECT [Product Group], Period,  
       Amount - LAG(Amount, 1,0) OVER (ORDER BY Period) AS Amount
FROM myTable 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...