SQL Server - 将每年分成4个周期

时间:2017-01-30 10:49:02

标签: sql asp.net sql-server

我想把这一年分成13个时期,每个时间为4周

一年52周/ 4 = 13周期

我希望每个时期都在星期六开始,并在星期五结束。

它应该如下图所示

enter image description here

显然我可以手动执行此操作,但日期会每年更改,我正在寻找一种使用SQL自动执行此操作的方法,而不是为每个即将到来的年份手动执行此操作

有没有办法自动生成这种年度分割?

3 个答案:

答案 0 :(得分:1)

this previous answer中,我展示了创建数字/日期表的方法。这样的桌子在很多地方非常漂亮。

使用这种方法你可以尝试这样的事情:

CREATE TABLE dbo.RunningNumbers(Number INT NOT NULL,CalendarDate DATE NOT NULL, CalendarYear INT NOT NULL,CalendarMonth INT NOT NULL,CalendarDay INT NOT NULL, CalendarWeek INT NOT NULL, CalendarYearDay INT NOT NULL, CalendarWeekDay INT NOT NULL);

DECLARE @CountEntries INT = 100000;
DECLARE @StartNumber INT = 0;


WITH E1(N) AS(SELECT 1 FROM(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(N)), --10 ^ 1
    E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b), -- 10 ^ 2 = 100 rows
    E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b), -- 10 ^ 4 = 10,000 rows
    E8(N) AS(SELECT 1 FROM E4 a CROSS JOIN E4 b), -- 10 ^ 8 = 10,000,000 rows
    CteTally AS
    (
        SELECT TOP(ISNULL(@CountEntries,1000000)) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) -1 + ISNULL(@StartNumber,0) As Nmbr
        FROM E8
    )
INSERT INTO dbo.RunningNumbers
SELECT CteTally.Nmbr,CalendarDate.d,CalendarExt.*
FROM CteTally
CROSS APPLY
(
    SELECT DATEADD(DAY,CteTally.Nmbr,{ts'1900-01-01 00:00:00'})
) AS CalendarDate(d)
CROSS APPLY
(
    SELECT YEAR(CalendarDate.d) AS CalendarYear
          ,MONTH(CalendarDate.d) AS CalendarMonth
          ,DAY(CalendarDate.d) AS CalendarDay
          ,DATEPART(WEEK,CalendarDate.d) AS CalendarWeek
          ,DATEPART(DAYOFYEAR,CalendarDate.d) AS CalendarYearDay
          ,DATEPART(WEEKDAY,CalendarDate.d) AS CalendarWeekDay
) AS CalendarExt;
GO

NTILE - SQL Server 2008+将创建(几乎)偶数块

这是实际查询

SELECT *,NTILE(13) OVER(ORDER BY CalendarDate) AS Periode
FROM RunningNumbers
WHERE CalendarWeekDay=6
AND CalendarDate>={d'2017-01-01'} AND CalendarDate <= {d'2017-12-31'};
GO
--Carefull with existing data!
--DROP TABLE dbo.RunningNumbers;

提示1:放置索引!

提示2:阅读有关NTILE的链接,尤其是备注 -section。

我认为这适合这种情况。您可以考虑使用Prdp的方法ROW_NUMBER()INT division同步。但是 - 大优势! - NTILE会允许PARTITION BY CalendarYear

提示3:您可以在表中添加一列

...您可以将期间的数字设置为固定值。这将使未来的查询变得非常简单,并允许在特殊情况下进行手动校正(第53周......)

答案 1 :(得分:1)

这是使用Calendar

的一种方法
DECLARE @start    DATE = '2017-04-01',
        @end_date DATE = '2017-12-31'

SET DATEFIRST 7;

WITH Calendar 
     AS (SELECT 1                      AS id,
                @start                 AS start_date,
                Dateadd(dd, 6, @start) AS end_date
         UNION ALL
         SELECT id + 1,
                Dateadd(week, 1, start_date),
                Dateadd(week, 1, end_date)
         FROM   Calendar 
         WHERE  end_date < @end_date)
SELECT id,
       ( Row_number()OVER(ORDER BY id) - 1 ) / 4 + 1 AS Period,
       start_date,
       end_date
FROM   Calendar 
OPTION (maxrecursion 0) 

我使用Recursive CTE生成了日期,但最好创建一个物理日历表,在这样的查询中使用它

答案 2 :(得分:0)

首先,一年中你将永远不会得到52周,大多数日历标准都有重叠周。你偶尔会得到53周。

您可以告诉SQL使用星期六作为datefirst的一周的第一天,然后在getdate()的今天运行datepart会告诉您一年中的一周:

  SET datefirst 6 -- 6 is Saturday
  SELECT datepart(ww,getdate()) as  currentWeek

然后您可以使用CEILING命令将此除以4以获得4周的分割:

  SET datefirst 6
  SELECT DATEPART(ww,getdate()) as  currentWeek,
  CEILING(DATEPART(ww,getdate())/4) as four_week_split