Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 当日期可能缺失时,以“周…”分组获取数据_Sql Server_Tsql - Fatal编程技术网

Sql server 当日期可能缺失时,以“周…”分组获取数据

Sql server 当日期可能缺失时,以“周…”分组获取数据,sql-server,tsql,Sql Server,Tsql,我在一个带有日期的表格中有数据,希望按周计算行数,例如2017-05-01的一周,其中结果是星期一开始的一周日期和匹配行数,即使该周没有行。这些都将在一个日期范围内 通过对DATEPARTwk进行分组,我可以很容易地将事情划分为几周,其中D是日期列,但我很难做到: 如何获取日期和填充的周,以及 如何在数据中没有匹配行的情况下保留一周的行 以下是按周分组: SET DATEFORMAT ymd; SET DATEFIRST 1; -- Monday is first day of week DE

我在一个带有日期的表格中有数据,希望按周计算行数,例如2017-05-01的一周,其中结果是星期一开始的一周日期和匹配行数,即使该周没有行。这些都将在一个日期范围内

通过对DATEPARTwk进行分组,我可以很容易地将事情划分为几周,其中D是日期列,但我很难做到:

如何获取日期和填充的周,以及

如何在数据中没有匹配行的情况下保留一周的行

以下是按周分组:

SET DATEFORMAT ymd;
SET DATEFIRST 1; -- Monday is first day of week

DECLARE @startDate DATETIME = '2017-05-01';
DECLARE @endDate DATETIME = '2017-07-01';

SELECT      DATEPART(wk, D) AS [Week Number], COUNT(*) AS [Count]
FROM        #temp
GROUP BY    DATEPART(wk, D)
ORDER BY    DATEPART(wk, D);
这给了我:

+−−−−−−−−−−−−−+−−−−−−−+ | Week Number | Count | +−−−−−−−−−−−−−+−−−−−−−+ | 19 | 5 | | 20 | 19 | | 22 | 8 | | 23 | 10 | | 24 | 5 | | 26 | 4 | +−−−−−−−−−−−−−+−−−−−−−+
为此,您必须生成一个表或CTE,其中包含星期一日期及其周数,如中所示,根据下面需要进行的操作进行了轻微修改,然后使用周数将数据按周分组,左连接或外应用该表或CTE:

SET DATEFORMAT ymd;
SET DATEFIRST 1;

DECLARE @startDate DATETIME = '2017-05-01';
DECLARE @endDate DATETIME = '2017-07-01';

;WITH Mondays AS (
    SELECT  @startDate AS D, DATEPART(WK, @startDate) AS W
    UNION ALL
    SELECT  DATEADD(DAY, 7, D), DATEPART(WK, DATEADD(DAY, 7, D))
    FROM    Mondays m
    WHERE   DATEADD(DAY, 7, D) < @endDate
)
SELECT      LEFT(CONVERT(NVARCHAR(MAX), Mondays.D, 120), 10) AS [Week Of], d.Count
FROM        Mondays
OUTER APPLY (
            SELECT  COUNT(*) AS [Count]
            FROM    #temp
            WHERE   DATEPART(WK, D) = W
            AND     D >= @startDate
            AND     D < @endDate
) d
ORDER BY    Mondays.D;
关于这一点,有两点需要注意:

我假设我们可以确保@startDate是星期一,这在查询之外很容易完成,或者如果需要备份到WEEKPARTWEEKDAY,@startDate是1,可以使用T-SQL中的简单循环完成。或者最坏的情况是,我们可以生成所有日期,然后用WEEKPARTWEEKDAY过滤它们

我假设日期范围总是一年或更短;否则,我们会有重复的周数。如果日期范围可能超过一年,请将周数与年数组合在一起,我们只使用上面的周数,例如DATEPARTYEAR,D*100+DATEPARTwk,D


为此,您必须生成一个表或CTE,其中包含星期一日期及其周数,如中所示,根据下面需要进行的操作进行了轻微修改,然后使用周数将数据按周分组,左连接或外应用该表或CTE:

SET DATEFORMAT ymd;
SET DATEFIRST 1;

DECLARE @startDate DATETIME = '2017-05-01';
DECLARE @endDate DATETIME = '2017-07-01';

;WITH Mondays AS (
    SELECT  @startDate AS D, DATEPART(WK, @startDate) AS W
    UNION ALL
    SELECT  DATEADD(DAY, 7, D), DATEPART(WK, DATEADD(DAY, 7, D))
    FROM    Mondays m
    WHERE   DATEADD(DAY, 7, D) < @endDate
)
SELECT      LEFT(CONVERT(NVARCHAR(MAX), Mondays.D, 120), 10) AS [Week Of], d.Count
FROM        Mondays
OUTER APPLY (
            SELECT  COUNT(*) AS [Count]
            FROM    #temp
            WHERE   DATEPART(WK, D) = W
            AND     D >= @startDate
            AND     D < @endDate
) d
ORDER BY    Mondays.D;
关于这一点,有两点需要注意:

我假设我们可以确保@startDate是星期一,这在查询之外很容易完成,或者如果需要备份到WEEKPARTWEEKDAY,@startDate是1,可以使用T-SQL中的简单循环完成。或者最坏的情况是,我们可以生成所有日期,然后用WEEKPARTWEEKDAY过滤它们

我假设日期范围总是一年或更短;否则,我们会有重复的周数。如果日期范围可能超过一年,请将周数与年数组合在一起,我们只使用上面的周数,例如DATEPARTYEAR,D*100+DATEPARTwk,D


这是另一种方法。我包括这一点,因为它将生成比递归CTE解决方案更少的读取,并且将非常快

WITH E(N) AS (SELECT 1 FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))x(x)),
iTally(N) AS 
(
  SELECT TOP (((DATEDIFF(day,@startdate, @endDate))/7)+1)
    (ROW_NUMBER() OVER (ORDER BY (SELECT 1))-1)
  FROM E a, E b, E c
)
SELECT WeekOf = DATEADD(WEEK,N,@startDate), [count] = COUNT(t.D)
FROM iTally i
LEFT JOIN #temp t ON t.D >= DATEADD(WEEK,N,@startDate) AND t.D < DATEADD(WEEK,N+1,@startDate)
GROUP BY DATEADD(WEEK,N,@startDate)
ORDER BY DATEADD(WEEK,N,@startDate); -- not required

这是另一种方法。我包括这一点,因为它将生成比递归CTE解决方案更少的读取,并且将非常快

WITH E(N) AS (SELECT 1 FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))x(x)),
iTally(N) AS 
(
  SELECT TOP (((DATEDIFF(day,@startdate, @endDate))/7)+1)
    (ROW_NUMBER() OVER (ORDER BY (SELECT 1))-1)
  FROM E a, E b, E c
)
SELECT WeekOf = DATEADD(WEEK,N,@startDate), [count] = COUNT(t.D)
FROM iTally i
LEFT JOIN #temp t ON t.D >= DATEADD(WEEK,N,@startDate) AND t.D < DATEADD(WEEK,N+1,@startDate)
GROUP BY DATEADD(WEEK,N,@startDate)
ORDER BY DATEADD(WEEK,N,@startDate); -- not required
你可以用这个

SET DATEFORMAT ymd;
SET DATEFIRST 1; -- Monday is first day of week

DECLARE @startDate DATETIME = '2017-05-01';
DECLARE @endDate DATETIME = '2017-07-01';

;WITH OrgResult AS ( -- Grouping result with missing week. Answer of the first question
    SELECT 
        DATEADD(DAY, 1 - DATEPART (WEEKDAY, D), D) [Week] -- Fist Day Of the Week
        , COUNT(*) [Count]
    FROM #temp
        WHERE D BETWEEN @startDate AND @endDate
    GROUP BY 
        DATEADD(DAY, 1 - DATEPART (WEEKDAY, D), D)
)
, Result AS -- Adds only missing weeks. Answer of the second question
(
    SELECT * FROM OrgResult
    UNION ALL
    SELECT DATEADD( DAY, 7, R.[Week] ), 0 [Count] 
    FROM Result R 
    WHERE NOT EXISTS( SELECT * FROM OrgResult O WHERE [Week] = DATEADD( DAY, 7, R.[Week] ) )
            AND DATEADD( DAY, 7, R.[Week] ) <= @endDate
)
SELECT * FROM Result
ORDER BY [Week]
你可以用这个

SET DATEFORMAT ymd;
SET DATEFIRST 1; -- Monday is first day of week

DECLARE @startDate DATETIME = '2017-05-01';
DECLARE @endDate DATETIME = '2017-07-01';

;WITH OrgResult AS ( -- Grouping result with missing week. Answer of the first question
    SELECT 
        DATEADD(DAY, 1 - DATEPART (WEEKDAY, D), D) [Week] -- Fist Day Of the Week
        , COUNT(*) [Count]
    FROM #temp
        WHERE D BETWEEN @startDate AND @endDate
    GROUP BY 
        DATEADD(DAY, 1 - DATEPART (WEEKDAY, D), D)
)
, Result AS -- Adds only missing weeks. Answer of the second question
(
    SELECT * FROM OrgResult
    UNION ALL
    SELECT DATEADD( DAY, 7, R.[Week] ), 0 [Count] 
    FROM Result R 
    WHERE NOT EXISTS( SELECT * FROM OrgResult O WHERE [Week] = DATEADD( DAY, 7, R.[Week] ) )
            AND DATEADD( DAY, 7, R.[Week] ) <= @endDate
)
SELECT * FROM Result
ORDER BY [Week]
Week        Count
----------- -----------
2017-05-01  5
2017-05-08  19
2017-05-15  0
2017-05-22  8
2017-05-29  10
2017-06-05  5
2017-06-12  0
2017-06-19  4
2017-06-26  0