2016-12-29 38 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