星期一的TSQL窗口函数

时间:2017-01-02 21:50:13

标签: sql-server-2008 sql-server-2012

我希望有一个查询累加在一个列上,但它需要每个星期一重新启动但看起来不可能用窗口函数来实现 这是我的代码:

    WITH t  (fecha, nombre_dia, distribuidor, monto)as (
SELECT CAST(t.fecha AS DATE)fecha
, CASE WHEN datename(dw,t.fecha)='Monday' then 1 else 2 end  nombre_dia
,d.NombreDistribuidor distribuidor
,sum(tr.Monto)monto

from HechosTransferencia tr inner join DimensionTiempo t on tr.DimensionTiempoId=t.DimensionTiempoId
inner join DimensionDistribuidor d on d.DimensionDistribuidorId=tr.DimensionDistribuidorId
WHERE        (t.Fecha BETWEEN DATEADD(MONTH, DATEDIFF(MONTH, - 2, GETDATE()) - 2, 0) AND GETDATE())
group by CAST(t.fecha AS DATE)
, CASE WHEN datename(dw,t.fecha)='Monday' then 1 else 2 end ,d.NombreDistribuidor
)SELECT *, 
SUM(monto) OVER(PARTITION BY nombre_dia, distribuidor
                ORDER BY fecha, nombre_dia, distribuidor  ROWS UNBOUNDED PRECEDING) AS RunningTotal
 from t where distribuidor='XYZ'

一个简单的输出样本将是

monday           XYZ    5      5
tuesday          XYZ    1      6
wednesday        XYZ    2      8
..
....
monday           XYZ    2       2         -- restart value every monday
tuesday          XYZ    2       4
..
...

2 个答案:

答案 0 :(得分:1)

我刚刚在rextester中设置了一个示例:http://rextester.com/MEXHM63945

不要试图在每个星期一打破累积金额,只需将星期一设置为星期的第一天,而将SUM()设置为提供者和WeekOfMonth。

我还没有测试过,但我认为你可以在不使用CTE窗口功能的情况下获得它。 (看看答案的结尾。)

-- Set monday first day of week
SET DATEFIRST 1;

create table #data ([date] datetime, provider varchar(10), value int);
insert into #data values
('2017-01-02', 'XYZ', 1),
('2017-01-03', 'XYZ', 5),
('2017-01-04', 'XYZ', 3),
('2017-01-05', 'XYZ', 5),
('2017-01-06', 'XYZ', 4),
('2017-01-07', 'XYZ', 11),
('2017-01-08', 'XYZ', 11),
('2017-01-09', 'XYZ', 1),
('2017-01-10', 'XYZ', 5),
('2017-01-11', 'XYZ', 3),
('2017-01-12', 'XYZ', 5),
('2017-01-13', 'XYZ', 4),
('2017-01-14', 'XYZ', 11),
('2017-01-15', 'XYZ', 11);


SELECT provider, DATEPART(WEEK, date) as week_of_year, value,  
       sum(value) OVER (Partition by provider, DATEPART(WEEK, date) ORDER BY date, provider) Acm
FROM #data
ORDER BY date, provider;

结果如下:

+----------+--------------+-------+-----+
| provider | week_of_year | value | Acm |
+----------+--------------+-------+-----+
|    XYZ   |       2      |   1   |  1  |
+----------+--------------+-------+-----+
|    XYZ   |       2      |   5   |  6  |
+----------+--------------+-------+-----+
|    XYZ   |       2      |   3   |  9  |
+----------+--------------+-------+-----+
|    XYZ   |       2      |   5   |  14 |
+----------+--------------+-------+-----+
|    XYZ   |       2      |   4   |  18 |
+----------+--------------+-------+-----+
|    XYZ   |       2      |   11  |  29 |
+----------+--------------+-------+-----+
|    XYZ   |       2      |   11  |  40 |
+----------+--------------+-------+-----+
|    XYZ   |       3      |   1   |  1  |
+----------+--------------+-------+-----+
|    XYZ   |       3      |   5   |  6  |
+----------+--------------+-------+-----+
|    XYZ   |       3      |   3   |  9  |
+----------+--------------+-------+-----+
|    XYZ   |       3      |   5   |  14 |
+----------+--------------+-------+-----+
|    XYZ   |       3      |   4   |  18 |
+----------+--------------+-------+-----+
|    XYZ   |       3      |   11  |  29 |
+----------+--------------+-------+-----+
|    XYZ   |       3      |   11  |  40 |
+----------+--------------+-------+-----+

我认为这应该可以胜任:

SELECT 
    CAST(t.fecha AS DATE) fecha
    , d.NombreDistribuidor distribuidor
    , SUM(tr.Monto) OVER (PARTITION BY d.NombreDistribuidor, DATEPART(week, CAST(t.fecha AS DATE))
                          ORDER BY CAST(t.fecha AS DATE), d.NombreDistribuidor) monto
FROM 
    HechosTransferencia tr 
    INNER JOIN DimensionTiempo t ON tr.DimensionTiempoId=t.DimensionTiempoId
    INNER JOIN DimensionDistribuidor d ON d.DimensionDistribuidorId=tr.DimensionDistribuidorId
WHERE        
    (t.Fecha BETWEEN DATEADD(MONTH, DATEDIFF(MONTH, - 2, GETDATE()) - 2, 0) AND GETDATE())
GROUP BY 
    CAST(t.fecha AS DATE), d.NombreDistribuidor;

答案 1 :(得分:1)

根据McNets提出的解决方案,我的问题的答案是:

SET DATEFIRST 1;

WITH t  (fecha, distribuidor, monto)as (
SELECT CAST(t.fecha AS DATE)fecha
,d.NombreDistribuidor distribuidor
,sum(tr.Monto)monto
 from HechosTransferencia tr inner join DimensionTiempo t on tr.DimensionTiempoId=t.DimensionTiempoId
inner join DimensionDistribuidor d on d.DimensionDistribuidorId=tr.DimensionDistribuidorId
WHERE        (t.Fecha BETWEEN DATEADD(MONTH, DATEDIFF(MONTH, - 2, GETDATE()) - 2, 0) AND GETDATE())
group by CAST(t.fecha AS DATE)
,d.NombreDistribuidor
)SELECT *
,sum(monto) OVER (Partition by distribuidor, DATEPART(WEEK, fecha) ORDER BY fecha, distribuidor)RunningTotal

 from t;