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
SQL Server SQL语句中的动态日期_Sql_Sql Server - Fatal编程技术网

SQL Server SQL语句中的动态日期

SQL Server SQL语句中的动态日期,sql,sql-server,Sql,Sql Server,提前感谢您在这方面的帮助 比如说,我有一个查询,可以比较不同年份的数据,从任意年份开始,一直持续到未来,从每年的同一时期到最后一个完成的月份,其特点是1月份的数据直到2月1日才显示出来。也就是说,不能使用T-SQL。有没有一种方法可以重新格式化下面的查询,从2008/01/01开始动态地生成日期,或者甚至在所有年份都这样做,并且永远不需要任何硬编码 select case when oact.fathernum like '112%' then sum(jdt1

提前感谢您在这方面的帮助

比如说,我有一个查询,可以比较不同年份的数据,从任意年份开始,一直持续到未来,从每年的同一时期到最后一个完成的月份,其特点是1月份的数据直到2月1日才显示出来。也就是说,不能使用T-SQL。有没有一种方法可以重新格式化下面的查询,从2008/01/01开始动态地生成日期,或者甚至在所有年份都这样做,并且永远不需要任何硬编码

select 
       case
         when oact.fathernum like '112%' then sum(jdt1.debit) - sum(jdt1.credit)
       end as [Accounts Receivable],
       jdt1.refdate as [Posting Date]
from jdt1
  inner join oact on jdt1.account = oact.AcctCode
where (oact.fathernum like '1%')
          and 
          (jdt1.refdate between '2008/01/01' and dateadd(day, -1, '2008/' + cast(month(getdate()) as varchar(2)) + '/01')
           or jdt1.refdate between '2009/01/01' and dateadd(day, -1, '2009/' + cast(month(getdate()) as varchar(2)) + '/01')
           or jdt1.refdate between '2010/01/01' and dateadd(day, -1, '2010/' + cast(month(getdate())  as varchar(2)) + '/01')
           or jdt1.refdate between '2011/01/01' and dateadd(day, -1, '2011/' + cast(month(getdate())  as varchar(2)) + '/01')
           or jdt1.refdate between '2012/01/01' and dateadd(day, -1, '2012/' + cast(month(getdate())  as varchar(2)) + '/01')
           or jdt1.refdate between '2013/01/01' and dateadd(day, -1, '2013/' + cast(month(getdate())  as varchar(2)) + '/01')
           or jdt1.refdate between '2014/01/01' and dateadd(day, -1, '2014/' + cast(month(getdate())  as varchar(2)) + '/01')
           or jdt1.refdate between '2015/01/01' and dateadd(day, -1, '2015/' + cast(month(getdate())  as varchar(2)) + '/01')
           or jdt1.refdate between '2016/01/01' and dateadd(day, -1, '2016/' + cast(month(getdate())  as varchar(2)) + '/01')
           or jdt1.refdate between '2017/01/01' and dateadd(day, -1, '2017/' + cast(month(getdate())  as varchar(2)) + '/01'))

group by oact.fathernum, jdt1.refdate

如果做不到这一点,有人愿意尝试在存储过程中使用T-SQL进行重新格式化来解决问题吗?只要是动态的,日期上限可以始终是当前年份。

从数字表开始生成日期集并在其上联接


这是为白天序列做的

会有类似的工作吗

YEAR(jdt1.refdate) between 2008 and 2017
  and
MONTH(jdt1.refdate) < MONTH(getdate())

下面的TSQL显示了一种构建动态日历表的方法。 如图所示的查询每年都会更改透视日期,但接下来将显示如何在特定年份固定日历“开始”日期

select 
       case
         when oact.fathernum like '112%' then sum(jdt1.debit) - sum(jdt1.credit)
       end as [Accounts Receivable],
       jdt1.refdate as [Posting Date]
from jdt1
inner join oact on jdt1.account = oact.AcctCode

inner join (select
    FirstDayOfYear  =DATEADD(m,datediff(m,0,getdate())-MONTH(getdate())+1,0),
    FirstDayOfMonth =DATEADD(m,datediff(m,0,getdate()),0)) D
inner join master..spt_values v on v.type='P'
    and v.number between 0 and 500 -- is 500 years enough? max=2047 from this table
  on jdt1.refdate >= DATEADD(year,v.number,D.FirstDayOfYear)
     and jdt1.refdate < DATEADD(year,v.number,D.FirstDayOfMonth)

where (oact.fathernum like '1%')
group by oact.fathernum, jdt1.refdate
两个轴心日期分别为**本年**的第一天和本年**本月的第一天。如果您需要**特定**年的第一天和当月但在同一特定年份的第一天,您可以使用以下示例中2008-01年1月的变化

select
    FirstDayOfYear  =cast('20080101' as datetime),
    FirstDayOfMonth =dateadd(m,month(getdate())-1,'20080101')
这将使用数据透视日期和内置的数字序列,每次逐步将1年添加到数据透视日期,从当前年份添加0开始

inner join master..spt_values v on v.type='P'
    and v.number between 0 and 500
  on jdt1.refdate >= DATEADD(year,v.number,D.FirstDayOfYear)
     and jdt1.refdate < DATEADD(year,v.number,D.FirstDayOfMonth)
我通常更喜欢

date >= A and date < B+1

无论B是否包含时间信息,它都有效。这对您的查询并不重要,但对于一致性来说是一个很好的实践。

如果您使用的是SQL Server 2005+,您只需动态构建日历即可:

With MaxDate As
    (
    Select Max(refdate) As [Date]
    From jdt1
    )
    , Calendar As
    (
    Select Cast( Cast(Year(GetDate())As char(4)) + '0101' As datetime ) As [StartDay]
        , DateAdd(d, -1, Cast( Cast(Year(GetDate()) + 1 As char(4)) + '0101' As datetime ) )As [EndDay]
    Union All
    Select DateAdd(yyyy, 1, [StartDay])
        , DateAdd(yyyy, 1, [EndDay])
    From Calendar
        Join MaxDate
            On Year(DateAdd(yyyy, 1, [EndDay])) <= Year(MaxDate.[Date])
    )
Select ...
From Calendar As C
    Join jdt1
        On jdt1.refdate Between C.StartDay And C.EndDay
    Join oact 
        On oact.AcctCode = jdt1.account
Where oct.fathernum Like '%1'
Group By oact.fathernum, jdt1.refdate       
Option ( MaxRecursion 0 );

在这个解决方案中,我从今天的年份开始,扩展到最后一个引用日期的年份。

另外:这对索引使用来说很糟糕,是吗?为什么?更重要的是,它应该是可怕的吗?因为要计算出第一部分,它需要在所有记录上运行一年来返回int值。根据jdt1.refdate测试的正确构造的日期范围只需收集1/12的数据。感谢@cyberwiki和@ypercubeIs这是sql server 2005或更高版本吗?令人印象深刻,谢谢!很高兴看到你是如何处理这个问题的,是的,500年应该足够了;很抱歉,我把你上面的尼克搞错了,所以习惯于看维基而不是猕猴桃。@cyberkiwi-这是一个很好的解决方案,我可以看到它的很多用途,但是有没有办法让它开始的一年不总是随着每一个新年而前进?我真的想从2008年开始。它正确地比较了每年的同一时期,我只是不知道如何修改它,将第一年固定在2008年,然后再从2008年开始比较接下来的每一年。换句话说,从2008年起的所有年份的同一时期数据必须同时预设。e、 例如,2008年1月1日至1月21日以及2009年1月1日至1月21日等。。有什么想法吗?我想出了一个解决办法。我把你的解决方案翻过来,从一个适当遥远的未来日期开始倒数,然后在where子句日期加法中倒数v.number的符号。我选择了2099,这是非常适合这个项目。再次感谢。@m7d-更新了答案,以满足保持起始年固定拍摄的要求,所以我不会奖励两个答案。哦,这也是一个很好的解决方案。谢谢
date >= A and date < B+1
With MaxDate As
    (
    Select Max(refdate) As [Date]
    From jdt1
    )
    , Calendar As
    (
    Select Cast( Cast(Year(GetDate())As char(4)) + '0101' As datetime ) As [StartDay]
        , DateAdd(d, -1, Cast( Cast(Year(GetDate()) + 1 As char(4)) + '0101' As datetime ) )As [EndDay]
    Union All
    Select DateAdd(yyyy, 1, [StartDay])
        , DateAdd(yyyy, 1, [EndDay])
    From Calendar
        Join MaxDate
            On Year(DateAdd(yyyy, 1, [EndDay])) <= Year(MaxDate.[Date])
    )
Select ...
From Calendar As C
    Join jdt1
        On jdt1.refdate Between C.StartDay And C.EndDay
    Join oact 
        On oact.AcctCode = jdt1.account
Where oct.fathernum Like '%1'
Group By oact.fathernum, jdt1.refdate       
Option ( MaxRecursion 0 );