2016-06-12 5 views
4

нужна помощь по следующим вопросам:SQL Server - Запуск Всего с переносом вперед

Таблица содержит Данные нужно открытие и закрытие запаса продукта в течение 5 дней

Таблица #BackData содержит некоторые почтовые от сделок

Как обновить таблицу #data с нарастающим итогом, включая перенос вперед

CREATE TABLE #Data ( 
    Prod VARCHAR(20) 
    ,SDate DATE 
    ,OStock INT 
    ,CStock INT 
    ) 

CREATE TABLE #BackData (
    Prod VARCHAR(20) 
    ,SDate DATE 
    ,CStock INT 
    ) 


INSERT INTO #Data 
SELECT 'p1', '2016-06-06', 10, 10 
UNION ALL 
SELECT 'p1', '2016-06-07', 10, 14 
UNION ALL 
SELECT 'p1', '2016-06-08', 14, 13 
UNION ALL 
SELECT 'p1', '2016-06-09', 13, 13 
UNION ALL 
SELECT 'p1', '2016-06-10', 13, 11 

INSERT INTO #BackData 
SELECT 'p1', '2016-06-06', 2 
UNION ALL 
SELECT 'p1', '2016-06-07', 4 
UNION ALL 
SELECT 'p1', '2016-06-09', -1 
UNION ALL 
SELECT 'p1', '2016-06-10', -2 

DROP TABLE #Data 
DROP TABLE #BackData 

Желаемая Выход:

Prod| SDate |OStock |CStock| 
p1 |2016-06-06 |10  |12 | 
p1 |2016-06-07 |12  |16 | 
p1 |2016-06-08 |16  |16 | 
p1 |2016-06-09 |16  |15 | 
p1 |2016-06-10 |15  |13 | 

EDIT

Это то, что я успел написать, прежде чем я получил ответ, используя два обновления, так как фактическая таблица слишком много столбцов, чтобы использовать в одном запросе.

UPDATE D 
SET D.CStock = FL.NewCStock 
FROM #Data D 
INNER JOIN (
    SELECT DT.Prod 
     ,DT.SDate 
     ,SUM(IIF(RwNm = 1, DT.CStock, 0) + ISNULL(BD.CStock, 0)) OVER (
      PARTITION BY DT.Prod ORDER BY DT.SDate ROWS UNBOUNDED PRECEDING 
      ) NewCStock 
    FROM (
     SELECT Prod 
      ,SDate 
      ,CStock 
      ,ROW_NUMBER() OVER (
       PARTITION BY Prod ORDER BY SDate 
       ) AS RwNm 
     FROM #Data 
     ) DT 
    LEFT JOIN #BackData BD ON DT.Prod = DT.Prod 
     AND BD.SDate = DT.SDate 
    ) FL ON D.Prod = FL.Prod 
    AND D.SDate = FL.SDate 

UPDATE D 
SET D.OStock = PV.NewOStock 
FROM #Data D 
INNER JOIN (
    SELECT Prod 
     ,SDate 
     ,ISNULL(LAG(CStock) OVER (
       PARTITION BY Prod ORDER BY SDate 
       ), CStock) AS NewOStock 
    FROM #Data 
    ) PV ON D.Prod = PV.Prod 
    AND D.SDate = PV.SDate 
+0

Какую версию SQL Server вы используете? – gofr1

+1

Можете ли вы объяснить, как вы получили эту две записи 'p1 | 2016-06-07 | 12 | 16' /' p1 | 2016-06-08 | 16 | 16'? –

+0

Как вы вывели на желаемом выходе для '2016-06-07'? – Squirrel

ответ

2

Вы можете использовать следующий запрос UPDATE:

;WITH ToUpdate AS (
    SELECT d1.OStock, d1.CStock, 
      COALESCE(LAG(d2.CStock2) OVER (PARTITION BY d2.Prod 
             ORDER BY d2.SDate), 
        d1.OStock) AS OStock2, 
      d2.CStock2 
    FROM #Data AS d1 
    JOIN (
     SELECT d.Prod, d.SDate, d.OStock, d.CStock, 
      COALESCE(t.newCStock, 
         LAG(t.newCStock) OVER (PARTITION BY d.Prod 
              ORDER BY d.SDate)) AS CStock2 
     FROM #Data AS d 
     LEFT JOIN (
     SELECT bd.Prod, bd.SDate, 
       drn.CStock + SUM(bd.CStock) OVER (PARTITION BY bd.Prod 
                ORDER BY bd.SDate) AS newCStock 
     FROM #BackData AS bd 
     INNER JOIN (
      SELECT Prod, CStock, 
        ROW_NUMBER() OVER (PARTITION BY Prod ORDER BY SDate) AS rn 
      FROM #Data 
     ) AS drn ON bd.Prod = drn.Prod AND drn.rn = 1 
    ) AS t ON t.Prod = d.Prod AND t.SDate = d.SDate 
    ) AS d2 ON d1.Prod = d2.Prod AND d1.SDate= d2.SDate 
) 
UPDATE ToUpdate 
SET OStock = OStock2, 
    CStock = CStock2 

Это выглядит ужасно запутанным, но я не мог думать ни о чем простой.

Demo here

+0

работает как очарование, большое спасибо. –

+0

Мне удалось сделать что-то подобное, однако я использовал два обновления. один для расчета закрывающего запаса, а затем запуск LAG для обновления исходного запаса. –

+0

@Romil Glad Я смог помочь и приветствовать Stack Overflow. Пожалуйста, отметьте этот или любой другой ответ как принятый, если он помог вам решить вашу проблему. –

1

Вы можете восстановить значения в #Data таблицы с помощью рекурсивного CTE:

;WITH cte AS (
SELECT top 1 d.Prod, 
     d.SDate, 
     d.OStock, 
     d.OStock + b.CStock as CStock 
FROM #Data d 
LEFT JOIN #BackData b 
    ON b.Prod = d.Prod and b.SDate = d.SDate 
ORDER BY d.SDate ASC 
UNION ALL 
SELECT c.Prod, 
     DATEADD(day,1,c.SDate), 
     c.CStock, 
     c.CStock + ISNULL(b.CStock,0) 
FROM cte c 
INNER JOIN #Data d 
    ON d.Prod = c.Prod AND d.SDate = DATEADD(day,1,c.SDate) 
OUTER APPLY (SELECT CStock FROM #BackData b WHERE b.Prod = d.Prod and b.SDate = d.SDate) as b 
) 

SELECT * 
FROM cte 

Выход:

Prod     SDate  OStock  CStock 
-------------------- ---------- ----------- ----------- 
p1     2016-06-06 10   12 
p1     2016-06-07 12   16 
p1     2016-06-08 16   16 
p1     2016-06-09 16   15 
p1     2016-06-10 15   13 

Чтобы обновить #Data:

UPDATE d 
SET OStock = c.OStock, CStock = c.CStock 
FROM #Data d 
INNER JOIN cte c 
    ON c.Prod = d.Prod AND c.SDate = d.SDate 
0

не должны быть результатом как:

Prod SDate  OStock CStock 
p1 2016-06-06  10  12 
p1 2016-06-07  12  20 (#Data CStock 14 + #BakData 2 + 4) 
p1 2016-06-08  20  19 (#Data CStock 13 + #BakData 2 + 4) 
p1 2016-06-09  19  18 (#Data CStock 13 + #BakData 2 + 4 - 1) 
p1 2016-06-10  18  14 (#Data CStock 11 + #BakData 2 + 4 - 1 -2) 

Этот запрос будет производить выше результат

update d 
set OStock = d.OStock + a.OAdj, 
    CStock = d.CStock + a.CAdj 
from #Data d 
    cross apply 
    (
     select OAdj = sum(case when Oflag = 1 then x.CStock else 0 end), 
      CAdj = sum(x.CStock) 
     from  
     (
      select *, Oflag = case when x.SDate = d.SDate then 0 else 1 end 
      from #BackData x 
      where x.Prod  = d.Prod 
      and x.SDate  <= d.SDate 
     ) x 
    ) a 
0

на основе ожидаемого выхода, кажется, что вы повторно вычисляя ежедневное открытие/Заключительный баланс на основе показателя от 2016-06-06

Вот решение, которое даст вам ожидаемый результат.

; with 
cte as 
(
    select Prod, SDate, OStock, CStock, 
      rn = row_number() over (partition by Prod order by SDate) 
    from #Data 
), 
adj as 
(
    select Prod, SDate, CStock 
    from cte 
    where rn = 1 
    union all 
    select Prod, SDate, CStock 
    from #BackData 
) 
update d 
set OStock = coalesce(o.OStock, d.OStock), 
    CStock = c.CStock 
from #Data d 
    cross apply 
    (
     select OStock = sum(x.CStock) 
     from adj x 
     where x.Prod = d.Prod 
     and x.SDate < d.SDate 
    ) o 
    cross apply 
    (
     select CStock = sum(x.CStock) 
     from adj x 
     where x.Prod = d.Prod 
     and x.SDate <= d.SDate 
    ) c 

Результат:

p1 2016-06-06 10 12 
p1 2016-06-07 12 16 
p1 2016-06-08 16 16 
p1 2016-06-09 16 15 
p1 2016-06-10 15 13