2016-12-29 71 views
1

我有一種方案,客戶每週(週一到週日)每天下訂單。但是,倉庫不會在週六/週日執行訂單。我有一面旗幟,告訴我一天是不是工作日(= 1)或不是(= 0)。我還有每天下的訂單。現在,倉庫希望在週一之前查看彙總的週末價值。這是原始選擇的摘錄(結果是來自事實表的cte-aggregate):T-SQL:根據字段值將數據移動到下一行

day  weekday qty 
01.12.2016 1  4551 
02.12.2016 1  4283 
03.12.2016 0  3925 
04.12.2016 0  4918 
05.12.2016 1  4905 
06.12.2016 1  4831 
07.12.2016 1  10920 
08.12.2016 1  2603 
09.12.2016 1  2578 
10.12.2016 0  2314 
11.12.2016 0  2932 
12.12.2016 1  3491 

關於5.12。我希望T-SQL事先做以下計算:

  1. 03.12 .: weekday = 0 - >將3925移動到下一行並將其添加到值04.12。製作03.12。 qty = 0
  2. 04.12 .: weekday = 0 - >將(3925 + 4918 = 8843)移動到下一行並將其添加到值05.12。 04.12。數量= 0
  3. 05.12:平日= 1 - >沒有移動到第二天,但只是 「收集」 的前幾天的數量:數量= 8843 + 4905 = 13748

結果是這樣的:

day  weekday qty 
    01.12.2016 1  4551 
    02.12.2016 1  4283 
    03.12.2016 0  0 
    04.12.2016 0  0 
    05.12.2016 1  13748 
    06.12.2016 1  4831 

限制:我對該數據庫沒有寫數據權限,因此沒有臨時表是可能的。

+1

什麼是sql-server的版本? – Viki888

+0

安裝了版本11.0.6544.0 – rasenkantenstein

+0

此外,我被授予使用臨時表的權利。 – rasenkantenstein

回答

1

變體1:您可以從agregated subqry視圖。

select 
    WorkDay, 
    sum (qty) SumQty, 
    sum (case when [weekday] = 1 then qty end) SumQtyOnlyWorkDay, 
    sum (case when [weekday] = 0 then qty end) SumQtyOnlyFreeDay 
from (
    select *, 
     [day] WorkDay 
    from SrcTable t 
    where [weekday] = 1 
    union all 
    select *, 
     (select top 1 [day] from @T d where d.[day] > t.[day] and d.[weekday] = 1 order by [day] asc) descendantWorkDay 
    from SrcTable t 
    where [weekday] = 0) m 
group by WorkDay 

解決方案只能在第一個工作日免費獲得。這可能是一個QRY像:

變2:

select *, 
    isnull((
     select top 1 [day] 
     from SrcTable d 
     where d.[day] > t.[day] 
      and d.[weekday] = 1 
      and t.[weekday] = 0 
     order by [day] asc), [day]) descendantWorkDay 
from SrcTable t 

隨着[日]字段索引。

嘗試避免CTE,當它不是必要的 - 做出最優化的qry很複雜(例如在第一個語句中使用排序函數強制執行計劃,並且下一個qry不能從索引獲益)。 CTE通常用於遞歸或全表連接或複雜的視圖。

+0

好的,需要工作日的其餘時間來弄清楚這裏發生了什麼:-)謝謝! – rasenkantenstein

0

假設您的sql server版本是2012或更高版本,您可以使用這2步過程。

注:該解決方案是基於在將day列被標記爲0行的最大的2天。如果0比如長週末,它將不會長時間工作。

首先,創建和填充示例表(保存我們這一步在你未來的問題)

DECLARE @T AS TABLE 
(
    day date, 
    weekday bit, 
    qty int 
) 

INSERT INTO @T VALUES 

('01.12.2016', 1, 4551), 
('02.12.2016', 1, 4283), 
('03.12.2016', 0, 3925), 
('04.12.2016', 0, 4918), 
('05.12.2016', 1, 4905), 
('06.12.2016', 1, 4831), 
('07.12.2016', 1, 10920), 
('08.12.2016', 1, 2603), 
('09.12.2016', 1, 2578), 
('10.12.2016', 0, 2314), 
('11.12.2016', 0, 2932), 
('12.12.2016', 1, 3491) 

然後用一對夫婦的common table expression s的caselag計算量。第一個將創建週末第二天的計算數量,第二天將創建一週的第一天的計算數量。

;WITH CTE1 AS 
(
    SELECT day, 
      weekday, 
      qty, 
      CASE WHEN weekday = 0 AND LAG(weekday) OVER (ORDER BY day) = 0 THEN 
       qty + LAG(qty) OVER (ORDER BY day) 
      ELSE 
       qty 
      END As calculated_qty 
    FROM @T 
), CTE2 AS 
(
    SELECT day, 
      weekday, 
      qty, 
      CASE WHEN weekday = 1 AND LAG(weekday) OVER (ORDER BY day) = 0 THEN 
       calculated_qty + LAG(calculated_qty) OVER (ORDER BY day) 
      ELSE 
       CASE WHEN weekday = 0 THEN 0 ELSE qty END 
      END As calculated_qty 
    FROM CTE1 
) 

SELECT * 
FROM CTE2 

結果:

day      weekday qty  calculated_qty 
12.01.2016 00:00:00  True 4551 4551 
12.02.2016 00:00:00  True 4283 4283 
12.03.2016 00:00:00  False 3925 0 
12.04.2016 00:00:00  False 4918 0 
12.05.2016 00:00:00  True 4905 13748 
12.06.2016 00:00:00  True 4831 4831 
12.07.2016 00:00:00  True 10920 10920 
12.08.2016 00:00:00  True 2603 2603 
12.09.2016 00:00:00  True 2578 2578 
12.10.2016 00:00:00  False 2314 0 
12.11.2016 00:00:00  False 2932 0 
12.12.2016 00:00:00  True 3491 8737 
+0

嗨,我會嘗試。聖誕節的時間通常有三個或更多的工作日= 0。安裝MSSQL 2014。 – rasenkantenstein

+0

因此,我的**註釋**在答案的頂部。這對於週末時間超過2天無效。 –

+0

我已被授予使用臨時表的權利。如果我使用某個版本的CTE1並循環播放,直到weekday = 0時沒有sum(qty)等於0?是這樣的可能嗎? – rasenkantenstein

0

由於您已被授予使用臨時表的權限。這應該適用於任何數量的非工作日。它遍歷整個表並使用if語句將[false]天放到下一個[true]日。我使用了Zohar發佈的表create語句。 (這是我的第一篇文章之一,所以我希望我發佈這個正確的)

DECLARE @T AS TABLE 
(
xday date, 
xweekday bit, 
qty int 
) 
DECLARE @result AS TABLE -- table to store results 
(
xday date, 
xweekday bit, 
qty int 
) 
INSERT INTO @T VALUES 

('12/01/2016', 1, 4551), 
('12/02/2016', 1, 4283), 
('12/03/2016', 0, 3925), 
('12/04/2016', 0, 4918), 
('12/05/2016', 1, 4905), 
('12/06/2016', 1, 4831), 
('12/07/2016', 1, 10920), 
('12/08/2016', 1, 2603), 
('12/09/2016', 1, 2578), 
('12/10/2016', 0, 2314), 
('12/11/2016', 0, 2932), 
('12/12/2016', 1, 3491) 

declare @xday date 
declare @xweekday bit 
declare @qty int 
declare @sumqty int = 0 -- temp column to hold [false day] qty values 

while exists (select * from @T) -- loop through table 
begin 
select top 1 @xday = xday, @xweekday = xweekday,@qty=qty from @T 
        order by xday asc 
set @sumqty = @sumqty + @qty 
if (@xweekday = 1) -- loop though holidays sum qty only 
BEGIN 
    INSERT INTO @result values (@xday,@xweekday,@sumqty) 
    set @sumqty = 0 
END 
else 
begin 
INSERT INTO @result values (@xday,@xweekday,0) 
end 
delete @T 
where xday = @xday 

end 

select * from @result 

should produce this. 
xday xweekday qty 
2016-12-01 1 4551 
2016-12-02 1 4283 
2016-12-03 0 0 
2016-12-04 0 0 
2016-12-05 1 13748 
2016-12-06 1 4831 
2016-12-07 1 10920 
2016-12-08 1 2603 
2016-12-09 1 2578 
2016-12-10 0 0 
2016-12-11 0 0 
2016-12-12 1 8737