Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/21.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
在T-SQL中创建会计日历_Sql_Sql Server_Tsql - Fatal编程技术网

在T-SQL中创建会计日历

在T-SQL中创建会计日历,sql,sql-server,tsql,Sql,Sql Server,Tsql,我正在尝试创建一个会计日历,其中会计年度从7月1日开始,一周定义为周一到周日 但例如,;如果一个月内一周的第一天是周六,那么周六到周日将被视为该月的一周,新的一周从周一开始,周日结束,依此类推 请参见下面我要创建的表格示例: 期间是指会计年度的月份 Week是该月的周数 开始日期(周开始日期)是一周开始的日期 结束日期(周结束日期)是一周结束的日期 星期几是开始日期和结束日期之间的日期 年 我在想,我需要一个程序,可能需要财政年度的第一天,然后迭代一年中的所有日子,添加列开始和结束日期、周

我正在尝试创建一个会计日历,其中会计年度从7月1日开始,一周定义为周一到周日

但例如,;如果一个月内一周的第一天是周六,那么周六到周日将被视为该月的一周,新的一周从周一开始,周日结束,依此类推

请参见下面我要创建的表格示例:

  • 期间是指会计年度的月份

  • Week是该月的周数
  • 开始日期(周开始日期)是一周开始的日期
  • 结束日期(周结束日期)是一周结束的日期
  • 星期几是开始日期和结束日期之间的日期

我在想,我需要一个程序,可能需要财政年度的第一天,然后迭代一年中的所有日子,添加列开始和结束日期、周数、期间和该天所属的年份

您不需要过程,但有些函数可能很方便

首先,请记住,某些日期时间函数依赖于@DATEFIRST。要使您的代码独立于此设置,您可以使用一个函数来规范化日数

CREATE FUNCTION getNormalizedWeekDay
(
      @inputDate DATE
    , @dateFirst TINYINT = 1
)
RETURNS SMALLINT
AS
BEGIN
    RETURN ((DATEPART(WEEKDAY, @inputDate) + @@DATEFIRST - 1 - @dateFirst) % 7) + 1;
END
在这种情况下,您可以知道要使用哪一天,并根据这一天计算结果。例如,可以方便地确定一天是否为星期天

如果我理解正确,您需要一个与内置函数行为类似的week函数,但将7月1日视为一年中的第一天

像这样的东西应该可以做到:

CREATE FUNCTION getFiscalWeekNumber
(
      @inputDate        DATE
    , @firstFiscalMonth TINYINT = 7
    , @dateFirst        TINYINT = 1
)
RETURNS TINYINT
AS
BEGIN
    /* NULL Input handling. */
    IF (@inputDate IS NULL) BEGIN
        RETURN NULL
    END

    DECLARE @inputDateWeekDay        TINYINT = getNormalizedWeekDay(@inputDate, @dateFirst);
    DECLARE @inputWeekStartDate      DATE    = DATEADD(DAY, -(@inputDateWeekDay-1), @inputDate);

    DECLARE @firstDayOfYear          DATE    = DATEFROMPARTS(getFiscalYear(@inputDate, @firstFiscalMonth), @firstFiscalMonth, 1);
    DECLARE @firstWeekStartDate      DATE    = @firstDayOfYear;
    DECLARE @weekDayOfFirstDayOfYear TINYINT = getNormalizedWeekDay(@firstDayOfYear, @dateFirst);

    -- The day is between the first day of year and the beginning of the second week -> 1st (partial) week for non-iso style
    IF (@inputDate >= @firstDayOfYear AND @inputDate < DATEADD(DAY, -(@weekDayOfFirstDayOfYear-1), DATEADD(DAY, 7, @firstWeekStartDate))) BEGIN
        RETURN 1;
    END

    -- Adjust the first day of the weeks to match with @dateFirst.
    SET @firstWeekStartDate = DATEADD(DAY, -(@weekDayOfFirstDayOfYear-1), @firstWeekStartDate);

    RETURN (DATEDIFF(DAY, @firstWeekStartDate, @inputWeekStartDate) / 7) + 1;
END
创建函数getFiscalWeekNumber
(
@输入日期
,@firstFiscalMonth TINYINT=7
,@dateFirst TINYINT=1
)
返回TINYINT
作为
开始
/*空输入处理*/
如果(@inputDate为空)开始
返回空值
结束
声明@inputDateWeekDay TINYINT=getNormalizedWeekDay(@inputDate,@dateFirst);
声明@inputWeekStartDate=DATEADD(天,-(@inputDateWeekDay-1),@inputDate);
声明@firstDayOfYear日期=DATEFROMPARTS(getFiscalYear(@inputDate,@firstFiscalMonth),@firstFiscalMonth,1);
声明@firstWeekStartDate=@firstDayOfYear;
声明@weekDayOfFirstDayOfYear TINYINT=getNormalizedWeekDay(@firstDayOfYear,@dateFirst);
--非iso样式的日期介于一年中的第一天和第二周开始之间->第一(部分)周
如果(@inputDate>=@firstDayOfYear和@inputDate

请记住,某些函数可能不存在于较旧版本的SQL Server中,我使用的是SQL Server 2016。

您可以使用
通用表表达式创建此表(
cte
)。这涉及到手动指定前10行(从值中选择t…
位),然后在第二次
cte
中将其交叉连接几次,以指数方式创建更多行。因为我有6个交叉连接(
tt1,tt2,tt3…
部分),我正在生成一百万行(
10^6
),然后计算出我在
top
子句中实际需要多少行,然后使用
row\u number
生成一个迭代列表,作为天数添加到周期开始日期

这是一个可以应用函数的日期表,它甚至可以跨多个财政年度工作。我建议您使用此选项创建
日期
查找表,而不是每次都运行:

declare @DateStart date = '20160701'
       ,@DateEnd   date = '20170630';

with t(t) as (select t from (values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) t(t))
    ,d(d) as (select top(datediff(d,@DateStart,@DateEnd)+1) dateadd(d,row_number() over (order by (select null))-1,@DateStart) from t t1,t t21,t t31,t t4,t t5,t t6)
select ((dense_rank() over (order by dateadd(m,datediff(m,0,d),0)) - 1) % 12) + 1 as [Period]

      ,dense_rank() over (partition by dateadd(m,datediff(m,0,d),0)
                          order by case when dateadd(d,1-datepart(dw,d),d) < dateadd(m,datediff(m,0,d),0)
                                        then dateadd(m,datediff(m,0,d),0)
                                        else dateadd(d,1-datepart(dw,d),d)
                                        end) as [Week]

      ,case when dateadd(d,1-datepart(dw,d),d) < dateadd(m,datediff(m,0,d),0)
            then dateadd(m,datediff(m,0,d),0)
            else dateadd(d,1-datepart(dw,d),d)
            end as StartDate

      ,case when dateadd(d,7-datepart(dw,d),d) > dateadd(m,datediff(m,0,d)+1,0)
            then dateadd(d,-1,dateadd(m,datediff(m,0,d)+1,0))
            else dateadd(d,7-datepart(dw,d),d)
            end as EndDate

      ,d as DayOfWeek
      ,year(d) as [Year]
from d
order by d;

还有另一种选择。这将产生50年,即0.703秒

示例

Set DateFirst  1

Declare @Date1 date = '2017-07-01'
Declare @Date2 date = '2019-06-30'


Select Period    = Dense_Rank() over (Partition By FY Order By FM)
      ,Week      = Dense_Rank() over (Partition By FY,FM Order By FW)
      ,StartDate = Min(D) over (Partition By FY,FM,FW )
      ,EndDate   = Max(D) over (Partition By FY,FM,FW )
      ,DayOfWeek = D
      ,Year      = FY
 From (
        Select FY = DatePart(Year,@Date1)-1+sum(case when convert(varchar(5),@Date1,101)=convert(varchar(5),D,101) then 1 else 0 end) over (Order By D)
              ,FM = sum(case when DatePart(Day,D)=DatePart(Day,@Date1) then 1 else 0 end) over (Order By D)
              ,FW = sum(case when DatePart(WeekDay,D)=1 then 1 else 0 end) over (Order By D)
              ,D
         From (
                Select Top (DateDiff(DAY,@Date1,@Date2)+1) 
                       D  = DateAdd(DAY,-1+Row_Number() Over (Order By (Select Null)),@Date1) 
                 From  master..spt_values n1,master..spt_values n2
              ) A1
      ) A
 Order By D

“周是那个月的周数。”你是指那个年的周数吗?把一周想象成一个月是有问题的。我明白你的意思。如果那会产生同样的结果,我们可以走@TabAllemanWell的路线,那就不会产生同样的结果。在一种情况下,week列将在每个月的某个任意点从1开始。另一方面,week列将上升到52,并在下一个财政年度的1开始。事实上,@TabAlleman,前者是我们正在努力实现的目标。这是问题的一部分。您需要包括一周应重置为1的规则。还有,当月份发生变化时,EndDate列会发生什么变化。什么是
calendar
引用?啊,对不起,我只是重写了一个脚本,但忘记了其中的架构名称。因此,应该将其更改为函数所在的架构。也就是说,当我运行脚本时,它出现在主架构中。我应该将其更改为主架构。将这些函数和表放在何处由您决定。我有一套表格和脚本,用于这些东西,它们通常位于日历模式中。这是一个更简单的解决方案,但是,当新周期开始时,周不会重置。它只会在新的财政年度重新设置starts@CastellJames我以为这是一年中的一周。只需将外部select语句中的
FY
更改为
FM
,即可轻松更改Monthahh的一周,对吗?@CastellJames请参阅更新的答案。。。这一周将重置#并在每一个FM中进行Beg/结束
Set DateFirst  1

Declare @Date1 date = '2017-07-01'
Declare @Date2 date = '2019-06-30'


Select Period    = Dense_Rank() over (Partition By FY Order By FM)
      ,Week      = Dense_Rank() over (Partition By FY,FM Order By FW)
      ,StartDate = Min(D) over (Partition By FY,FM,FW )
      ,EndDate   = Max(D) over (Partition By FY,FM,FW )
      ,DayOfWeek = D
      ,Year      = FY
 From (
        Select FY = DatePart(Year,@Date1)-1+sum(case when convert(varchar(5),@Date1,101)=convert(varchar(5),D,101) then 1 else 0 end) over (Order By D)
              ,FM = sum(case when DatePart(Day,D)=DatePart(Day,@Date1) then 1 else 0 end) over (Order By D)
              ,FW = sum(case when DatePart(WeekDay,D)=1 then 1 else 0 end) over (Order By D)
              ,D
         From (
                Select Top (DateDiff(DAY,@Date1,@Date2)+1) 
                       D  = DateAdd(DAY,-1+Row_Number() Over (Order By (Select Null)),@Date1) 
                 From  master..spt_values n1,master..spt_values n2
              ) A1
      ) A
 Order By D