对于我正在工作的当前项目,我需要根据日期范围返回汇总报告。
我有3种类型的报告,每年,每月和每日。
为了帮助返回此报告,我需要一个能够在很大范围内返回日期时间的所有子范围的函数。
因此,例如,如果我在“2006-01-01 11:10:00”和“2006-01-05 08:00:00”之间的所有日常范围,我会期望以下结果。
select *
from dbo.fnGetDateRanges('d', '2006-01-01 11:10:00', '2006-01-05 08:00:00')
2006-01-01 11:10:00.000, 2006-01-02 00:00:00.000
2006-01-02 00:00:00.000, 2006-01-03 00:00:00.000
2006-01-03 00:00:00.000, 2006-01-04 00:00:00.000
2006-01-04 00:00:00.000, 2006-01-05 00:00:00.000
2006-01-05 00:00:00.000, 2006-01-05 08:00:00.000
对于'2006-01-01 11:10:00'到'2009-05-05 08:00:00'的年度范围,我希望。
select *
from dbo.fnGetDateRanges('y', '2006-01-01 11:10:00', '2009-05-05 08:00:00')
2006-01-01 11:10:00.000, 2007-01-01 00:00:00.000
2007-01-01 00:00:00.000, 2008-01-01 00:00:00.000
2008-01-01 00:00:00.000, 2009-01-01 00:00:00.000
2009-01-01 00:00:00.000, 2009-05-05 08:00:00.000
我该如何实现这个功能?
答案 0 :(得分:3)
静态数字表很有用,单列,比如8000行FROM 0到7999
(未选中)
DECLARE @Start smalldatetime, @End smalldatetime, @Diff int
SELECT @Start = '2006-01-01 11:10:00', @End = '2009-05-05 08:00:00', @diff = DATEDIFF(year,@start,@end)
SELECT
DATEADD(year,N.Number,@Start)
FROM
dbo.Number N
WHERE
N.Number <= @diff
答案 1 :(得分:2)
这里有很多技巧,希望你发现它很有用
create function dbo.fnGetDateRanges
(
@type char(1),
@start datetime,
@finish datetime
)
returns @ranges table(start datetime, finish datetime)
as
begin
declare @from datetime
declare @to datetime
set @from = @start
if @type = 'd'
begin
set @to = dateadd(day, 1,
convert
( datetime,
cast(DatePart(d,@start) as varchar) + '/' + cast(DatePart(m,@start) as varchar) + '/' + cast(DatePart(yy,@start) as varchar),
103
)
)
end
if @type = 'm'
begin
set @to = dateadd(month, 1,
convert
(
datetime,
'1/' + cast(DatePart(m,@start) as varchar) + '/' + cast(DatePart(yy,@start) as varchar),
103
)
)
end
if @type = 'y'
begin
set @to = dateadd(year, 1,
convert
(
datetime,
'1/1/' + cast(DatePart(yy,@start) as varchar),
103
)
)
end
while @to < @finish
begin
insert @ranges values (@from, @to)
set @from = @to
if @type = 'd'
set @to = dateadd(day, 1, @to)
if @type = 'm'
set @to = dateadd(month, 1, @to)
if @type = 'y'
set @to = dateadd(year, 1, @to)
end
insert @ranges values (@from, @finish)
return
end
答案 2 :(得分:1)
如果您更喜欢基于集合的解决方案,请使用以下链接中显示的策略来生成从x到y的一系列数值。然后,使用DATEADD()和您自己的自定义限制加入它,以创建天,月,季,年或其他任何范围。我发现将此范围查询作为视图很有帮助。
答案 3 :(得分:1)
从性能角度来看,您不希望使用函数来生成日期范围。对于查询中的每个评估(@myDate > dbo.MyFunc()
),该函数必须完全执行。你最好的办法是建立静态数字表。
现在开始使用数字表....
这是创建整数表的快捷方法。 (Jeff Moden的道具伎俩道具)
SELECT TOP 1000000
IDENTITY(INT,1,1) as N
INTO dbo.NumbersTable
FROM Master.dbo.SysColumns
Master.dbo.SysColumns
在表格中填充1000000个数字的时间不到2秒。
现在要解决您的问题,您需要使用它来构建日期表。以下示例将从@startDate
开始创建一个每小时0小时(12AM)的表格DECLARE @DaysFromStart int
DECLARE @StartDate datetime
SET @StartDate = '10/01/2008'
SET @ DaysFromStart = (SELECT (DATEDIFF(dd,@StartDate,GETDATE()) + 1))
CREATE TABLE [dbo].[TableOfDates](
[fld_date] [datetime] NOT NULL,
CONSTRAINT [PK_TableOfDates] PRIMARY KEY CLUSTERED
(
[fld_date] ASC
)WITH FILLFACTOR = 99 ON [PRIMARY]
) ON [PRIMARY]
INSERT INTO
dbo.TableOfDates
SELECT
DATEADD(dd,nums.n - @DaysFromStart ,CAST(FLOOR(CAST(GETDATE() as FLOAT)) as DateTime)) as FLD_Date
FROM #NumbersTable nums
SELECT MIN(FLD_Date) FROM dbo.TableOfDates
SELECT MAX(FLD_Date) FROM dbo.TableOfDates
现在使用DATEADD / DIFF的不同组合,您应该能够创建有效执行许多日期范围查询所需的静态表。