我编写了以下查询...但是我很难将其转换为函数,因为有几个原因......(1)因为它包含动态SQL而且我不确定函数是否允许动态SQL,以及(2)因为我使用临时表来存储输出数据。我尝试将它转换为表变量而没有运气。查询的要点是采用任意两个日期时间范围和增量类型(月,日,年,小时等),并吐出一个包含所提供范围的日期范围表。
查询的原因是因为我必须为报表服务器编写大量报表,并且报表请求多次要按小时,日,周,月等进行分解,而且我经常要编写相同的报表反复查询以生成日期范围表。我使用这些表来保持连接,以便我的最终输出不会跳过任何日期范围,以防没有该范围的数据,它仍将正确填写零和图表/图表。
我认为没有办法让这个代码在一个函数中运行,除非有一个完全不同的编写方式(编辑,请看更新)...我敢肯定我可以去长期复杂有一些长的案例陈述的路线,而不是只有每个增量类型(秒,分钟,小时,日,周,月,季,年),然后我可以消除动态SQL。也许我可以使用递归CTE并消除while循环。但我对这些没有任何经验。
以下是代码:
DECLARE @DateFrom DATETIME = '2017-01-01',
@DateTo DATETIME = '2017-02-02 23:59:59.997',
@Increment VARCHAR(20) = 'mm'
DECLARE @SQL NVARCHAR(MAX) = NULL
IF OBJECT_ID('tempdb..#DateRange') IS NOT NULL DROP TABLE #DateRange --SELECT * FROM #DateRange
CREATE TABLE #DateRange (BeginDate DATETIME, EndDate DATETIME)
SELECT @SQL = '
DECLARE @TargetDate DATETIME = ''' + CONVERT(VARCHAR, @DateFrom, 121) + '''
IF DATEDIFF('+ @Increment +', ''' + CONVERT(VARCHAR, @DateFrom, 121) + ''', ''' + CONVERT(VARCHAR, @DateTo, 121) + ''') > 2000 RETURN
WHILE (1=1)
BEGIN
INSERT INTO #DateRange
SELECT BeginDate = DATEADD('+ @Increment +', DATEDIFF('+ @Increment +', 0, @TargetDate) , 0)
, EndDate = DATEADD(ms, -3, DATEADD('+ @Increment +', DATEDIFF('+ @Increment +', 0, @TargetDate) + 1, 0))
SET @TargetDate = DATEADD('+ @Increment +', 1, @TargetDate)
IF @TargetDate > ''' + CONVERT(VARCHAR, @DateTo, 121) + ''' BREAK
END'
EXEC sp_executesql @SQL
SELECT * FROM #DateRange
编辑:这是一个修改过的版本,不确定这是否会被认为是“更好”,但至少它会消除动态SQL,我可以将它作为一个函数使用。
EDIT2:由于运行速度更快,我将限制更改为返回的5000条记录。我也改变了它运行的方向,所以它从DateTo开始并向后工作。这样当它达到极限时,它只会停止到目前为止。我还添加了一些安全性,比如检查增量(不确定还有什么叫它?)选项值。我讨厌这个巨大的案例陈述,但我没有看到任何其他方法去做。
CREATE FUNCTION dbo.uf_DateRange (
@DateFrom DATETIME,
@DateTo DATETIME,
@Increment VARCHAR(20)
)
RETURNS @Return TABLE (
BeginDate DATETIME,
EndDate DATETIME
)
AS
BEGIN
IF @Increment NOT IN ('year','yy','yyyy','quarter','qq','q','month','mm','m','week','wk','ww','day','dd','d','hour','hh','minute','mi','n','second','ss','s') RETURN
DECLARE @TargetDate DATETIME = @DateTo,
@LoopLimit INT = 5000,
@Counter INT = 0
DECLARE @DateRange TABLE (BeginDate DATETIME, EndDate DATETIME)
WHILE (@Counter < @LoopLimit)
BEGIN
INSERT INTO @Return (BeginDate, EndDate)
SELECT BeginDate = CASE WHEN @Increment IN ('year' , 'yy', 'yyyy') THEN DATEADD(yy, DATEDIFF(yy, 0, @TargetDate), 0)
WHEN @Increment IN ('quarter', 'qq', 'q' ) THEN DATEADD(qq, DATEDIFF(qq, 0, @TargetDate), 0)
WHEN @Increment IN ('month' , 'mm', 'm' ) THEN DATEADD(mm, DATEDIFF(mm, 0, @TargetDate), 0)
WHEN @Increment IN ('week' , 'wk', 'ww' ) THEN DATEADD(ww, DATEDIFF(ww, 0, @TargetDate), 0)
WHEN @Increment IN ('day' , 'dd', 'd' ) THEN DATEADD(dd, DATEDIFF(dd, 0, @TargetDate), 0)
WHEN @Increment IN ('hour' , 'hh' ) THEN DATEADD(hh, DATEDIFF(hh, 0, @TargetDate), 0)
WHEN @Increment IN ('minute' , 'mi', 'n' ) THEN DATEADD(mi, DATEDIFF(mi, 0, @TargetDate), 0)
WHEN @Increment IN ('second' , 'ss', 's' ) THEN DATEADD(ss, DATEDIFF(ss, 0, @TargetDate), 0)
END
, EndDate = DATEADD(ms, -3,
CASE WHEN @Increment IN ('year' , 'yy', 'yyyy') THEN DATEADD(yy, DATEDIFF(yy, 0, @TargetDate) + 1, 0)
WHEN @Increment IN ('quarter', 'qq', 'q' ) THEN DATEADD(qq, DATEDIFF(qq, 0, @TargetDate) + 1, 0)
WHEN @Increment IN ('month' , 'mm', 'm' ) THEN DATEADD(mm, DATEDIFF(mm, 0, @TargetDate) + 1, 0)
WHEN @Increment IN ('week' , 'wk', 'ww' ) THEN DATEADD(ww, DATEDIFF(ww, 0, @TargetDate) + 1, 0)
WHEN @Increment IN ('day' , 'dd', 'd' ) THEN DATEADD(dd, DATEDIFF(dd, 0, @TargetDate) + 1, 0)
WHEN @Increment IN ('hour' , 'hh' ) THEN DATEADD(hh, DATEDIFF(hh, 0, @TargetDate) + 1, 0)
WHEN @Increment IN ('minute' , 'mi', 'n' ) THEN DATEADD(mi, DATEDIFF(mi, 0, @TargetDate) + 1, 0)
WHEN @Increment IN ('second' , 'ss', 's' ) THEN DATEADD(ss, DATEDIFF(ss, 0, @TargetDate) + 1, 0)
END)
SET @TargetDate = CASE WHEN @Increment IN ('year' , 'yy', 'yyyy') THEN DATEADD(yy, -1, @TargetDate)
WHEN @Increment IN ('quarter', 'qq', 'q' ) THEN DATEADD(qq, -1, @TargetDate)
WHEN @Increment IN ('month' , 'mm', 'm' ) THEN DATEADD(mm, -1, @TargetDate)
WHEN @Increment IN ('week' , 'wk', 'ww' ) THEN DATEADD(ww, -1, @TargetDate)
WHEN @Increment IN ('day' , 'dd', 'd' ) THEN DATEADD(dd, -1, @TargetDate)
WHEN @Increment IN ('hour' , 'hh' ) THEN DATEADD(hh, -1, @TargetDate)
WHEN @Increment IN ('minute' , 'mi', 'n' ) THEN DATEADD(mi, -1, @TargetDate)
WHEN @Increment IN ('second' , 'ss', 's' ) THEN DATEADD(ss, -1, @TargetDate)
END
IF @TargetDate > @DateTo BREAK
SET @Counter += 1
END
RETURN
END
GO
答案 0 :(得分:0)
你将在这里遇到一系列限制。我的理解是一个函数不能执行一个sproc,所以这是一个很大的显示停止。此外,您不能使用函数执行INSERT(或UPDATE或DELETE),因此还有另一个大问题。
是否有特定原因您不能将其作为程序留下?