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