【问题标题】:13 Period Calendar 4-4-5 Calendar T-SQL MSSQL13 期间日历 4-4-5 日历 T-SQL MSSQL
【发布时间】:2018-08-28 03:16:44
【问题描述】:

我正在尝试在 mssql 中创建一个 13 个周期的日历,但我有点卡住了。我不确定我的方法是否是实现这一目标的最佳方法。我有我的基本脚本,如下所示:

Set DateFirst  1

Declare @Date1 date = '20180101' --startdate should always be start of 
financial year
Declare @Date2 date = '20181231' --enddate should always be start of 
financial year

SELECT * INTO #CalendarTable
FROM dbo.CalendarTable(@Date1,@Date2,0,0,0)c
DECLARE @StartDate datetime,@EndDate datetime

SELECT @StartDate=MIN(CASE WHEN [Day]='Monday' THEN [Date] ELSE NULL END),
@EndDate=MAX([Date])
FROM #CalendarTable

;With Period_CTE(PeriodNo,Start,[End])
AS
(SELECT 1,@StartDate,DATEADD(wk,4,@StartDate) -1
UNION ALL
SELECT PeriodNo+1,DATEADD(wk,4,Start),DATEADD(wk,4,[End])
FROM Period_CTE
WHERE DATEADD(wk,4,[End])< =@EndDate
OR PeriodNo+1 <=13
)
select * from Period_CTE

这给了我这个:

PeriodNo Start End 1 2018-01-01 00:00:00.000 2018-01-28 00:00:00.000 2 2018-01-29 00:00:00.000 2018-02-25 00:00:00.000 3 2018-02-26 00:00:00.000 2018-03-25 00:00:00.000 4 2018-03-26 00:00:00.000 2018-04-22 00:00:00.000 5 2018-04-23 00:00:00.000 2018-05-20 00:00:00.000 6 2018-05-21 00:00:00.000 2018-06-17 00:00:00.000 7 2018-06-18 00:00:00.000 2018-07-15 00:00:00.000 8 2018-07-16 00:00:00.000 2018-08-12 00:00:00.000 9 2018-08-13 00:00:00.000 2018-09-09 00:00:00.000 10 2018-09-10 00:00:00.000 2018-10-07 00:00:00.000 11 2018-10-08 00:00:00.000 2018-11-04 00:00:00.000 12 2018-11-05 00:00:00.000 2018-12-02 00:00:00.000 13 2018-12-03 00:00:00.000 2018-12-30 00:00:00.000

我想要得到的结果是

即使我必须采取不同的方法我也不介意,只要结果与上述相同。

dbo.CalendarTable() 是一个返回以下结果的函数。如果需要,我可以分享代码。

【问题讨论】:

  • 你走错了方向。从您的 DayOfWeek 列开始,然后使用函数/子选择来获取其他列。
  • 我没有收到星期一的部分? dbo.CalendarTable 来自哪里?
  • 我更新了帖子。 dbo.CalendarTable 是一个函数。

标签: sql-server date tsql datetime calendar


【解决方案1】:

我将创建一个通用数字表 like suggested here 并添加一个列 Periode13

获得平铺的诀窍是整数除法:

DECLARE @PeriodeSize INT=28; --13 "moon-months" a 28 days

SELECT TOP 100 (ROW_NUMBER() OVER(ORDER BY (SELECT NULL))-1)/@PeriodeSize
FROM master..spt_values --just a table with many rows to show the principles

您可以使用简单的更新语句将其添加到现有的数字表中。

更新一个完整的工作示例(使用上面链接的逻辑)

DECLARE @RunningNumbers TABLE  (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 @RunningNumbers
SELECT CteTally.Nmbr,CalendarDate.d,CalendarExt.*
FROM CteTally
CROSS APPLY
(
    SELECT DATEADD(DAY,CteTally.Nmbr,{ts'2018-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;

--上面的模型表现在已经填满,可以查询了

 WITH AddPeriode AS
(
    SELECT     Number/28 +1 AS PeriodNumber
              ,CalendarDate
              ,CalendarWeek
              ,r.CalendarDay 
              ,r.CalendarMonth 
              ,r.CalendarWeekDay 
              ,r.CalendarYear 
              ,r.CalendarYearDay 
    FROM @RunningNumbers AS r
)
SELECT TOP 100 p.*
          ,(SELECT MIN(CalendarDate) FROM AddPeriode AS x WHERE x.PeriodNumber=p.PeriodNumber) AS [Start]
          ,(SELECT MAX(CalendarDate) FROM AddPeriode AS x WHERE x.PeriodNumber=p.PeriodNumber) AS [End]
          ,(SELECT MIN(CalendarDate) FROM AddPeriode AS x WHERE x.PeriodNumber=p.PeriodNumber AND x.CalendarWeek=p.CalendarWeek) AS [wkStart]
          ,(SELECT MAX(CalendarDate) FROM AddPeriode AS x WHERE x.PeriodNumber=p.PeriodNumber AND x.CalendarWeek=p.CalendarWeek) AS [wkEnd]
          ,(ROW_NUMBER() OVER(PARTITION BY PeriodNumber ORDER BY CalendarDate)-1)/7+1 AS WeekOfPeriode
FROM AddPeriode AS p
ORDER BY CalendarDate

试试看……

提示:不要为此使用VIEWiTVF

这是不变的数据,最好放在具有适当索引的物理存储表中。

【讨论】:

  • 感谢 Shnugo,但我不确定这对我有什么帮助。你能用你的方法展示我的结果集的例子吗?对我造成问题的列是 wkStartDate、wkEndDate、weekofperiod 和 weekofyear。如果我能以某种方式确定 wkStartDate 和 wkEndDate。我想我应该能够使用窗口函数来获取其他两个。
  • 这真的很有帮助。谢谢。然而有一个问题。我一直在尝试修改此脚本以输出 13 个句点而不是 14 个。目前这是向上吐出 14 个周期而不是 13 个周期,即 4-4-5 日历。这比我预期的要诡计多端。
  • @CastellJames 我必须承认我以前与这种日历毫无关系。我的建议是:使用上述脚本尽可能接近地创建日历。将此复制到 Excel 并手动修改。然后将其复制回物理表中。为未来 20 年创建一个物理存储列表。这将需要几个小时 - 但创建一个完全魔术特殊情况感知奇迹脚本需要更长的时间......
  • @CastellJames 关于14 周期向上的提示。只需使用 模运算符(如(Periode-1) % 13)。这将开始从 0 到 12 一遍又一遍地计数......
  • 感谢您对此的帮助。你帮了大忙。
【解决方案2】:

不太确定此处是否接受外部链接,但我写了一篇文章,其中包含所有代码的 5-4-4 财政年度“作物年”。随意使用这些文章中的所有代码。

SQL Server Calendar Table

SQL Server Calendar Table: Fiscal Years

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-20
    • 2021-01-02
    • 1970-01-01
    • 1970-01-01
    • 2018-09-02
    • 2013-02-22
    相关资源
    最近更新 更多