T-SQL:根据字段值

时间:2016-12-29 08:48:00

标签: sql-server loops tsql

我有一个场景,客户每周都会下订单(周一到周日)。但是,仓库不会在周六/周日进行订单。我有一个标志告诉我一天是否是工作日(= 1)或不是(= 0)。此外,我每天都有订单。现在,仓库希望在星期一之后看到聚合的周末价值。这是原始选择的摘录(结果是来自事实表的cte-aggregate):

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。:工作日= 0 - >将3925移动到下一行并将其添加到值04.12。制作03.12。 qty = 0
  2. 04.12。:工作日= 0 - >将(3925 + 4918 = 8843)移动到下一行并将其添加到05.12的值。制作04.12。数量= 0
  3. 05.12。:工作日= 1 - >什么都不移动到第二天,但只是“收集”前几天的数量:qty = 8843 + 4905 = 13748
  4. 结果如下:

      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
    

    限制:我对该数据库没有写入数据权限,因此无法使用临时表。

3 个答案:

答案 0 :(得分: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通常用于递归或全表连接或复杂视图。

答案 1 :(得分:0)

假设您的sql server版本是2012或更高版本,您可以使用此两步流程。

注意:此解决方案最多连续2天,day列标记为0。如果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 expressioncaselag的几个custom Auth Provider来计算数量。第一个将创建周末第二天的计算数量,第二个将创建一周第一天的计算数量。

;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

答案 2 :(得分:0)

由于您已被授予使用临时表的权限。这适用于任何数量的非工作日。它遍历表并使用if语句将[false]天放到下一个[true]天 我用Zohar发布的表创建语句。 (这是我的第一篇帖子,所以我希望我能正确发布这个帖子)

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