有没有办法在SQL中完成这样的事情:
DECLARE @iter = 1
WHILE @iter<11
BEGIN
DECLARE @('newdate'+@iter) DATE = [some expression that generates a value]
SET @iter = @iter + 1
END
最后我会有10个变量:
@newdate1
@newdate2
@newdate3
@newdate4
@newdate5
@newdate6
@newdate7
@newdate8
@newdate9
@newdate10
更新
根据评论,我想我应该指定为什么我想这样做。我正在使用Report Builder 3.0。我将做一个报告,其中输入将是start date
和end date
(除了另一个参数)。这将生成日期范围之间的数据。但是,用户还希望检查2013年集中所有其他年份的相同日期范围 - &gt;当年。
棘手的部分是:用户可以在2013年和当前年份之间输入任何年份的日期范围,我需要返回输入年份的数据以及其他年份的数据。例如,如果用户在2014年1月1日 - 2014年6月1日输入,那么我需要返回相同的范围,但是对于2013年,2015年和2016年。
示例输入:
1/1/2016 - 6/1/2016
报告必须为这些值生成数据:
1/1/2013 - 6/1/2013
1/1/2014 - 6/1/2014
1/1/2015 - 6/1/2015
1/1/2016 - 6/1/2016
如果有更好的方法可以做到这一点,我全心全意。
答案 0 :(得分:3)
我使用UDF创建动态日期范围。
对于exanple
Select DateR1=RetVal,DateR2=DateAdd(MM,5,RetVal) from [dbo].[udf-Create-Range-Date]('2013-01-01','2016-01-01','YY',1)
返回
DateR1 DateR2
2013-01-01 2013-06-01
2014-01-01 2014-06-01
2015-01-01 2015-06-01
2016-01-01 2016-06-01
UDF
CREATE FUNCTION [dbo].[udf-Create-Range-Date] (@DateFrom datetime,@DateTo datetime,@DatePart varchar(10),@Incr int)
Returns
@ReturnVal Table (RetVal datetime)
As
Begin
With DateTable As (
Select DateFrom = @DateFrom
Union All
Select Case @DatePart
When 'YY' then DateAdd(YY, @Incr, df.dateFrom)
When 'QQ' then DateAdd(QQ, @Incr, df.dateFrom)
When 'MM' then DateAdd(MM, @Incr, df.dateFrom)
When 'WK' then DateAdd(WK, @Incr, df.dateFrom)
When 'DD' then DateAdd(DD, @Incr, df.dateFrom)
When 'HH' then DateAdd(HH, @Incr, df.dateFrom)
When 'MI' then DateAdd(MI, @Incr, df.dateFrom)
When 'SS' then DateAdd(SS, @Incr, df.dateFrom)
End
From DateTable DF
Where DF.DateFrom < @DateTo
)
Insert into @ReturnVal(RetVal) Select DateFrom From DateTable option (maxrecursion 32767)
Return
End
-- Syntax Select * from [dbo].[udf-Create-Range-Date]('2016-10-01','2020-10-01','YY',1)
-- Syntax Select * from [dbo].[udf-Create-Range-Date]('2016-10-01','2020-10-01','DD',1)
-- Syntax Select * from [dbo].[udf-Create-Range-Date]('2016-10-01','2016-10-31','MI',15)
-- Syntax Select * from [dbo].[udf-Create-Range-Date]('2016-10-01','2016-10-02','SS',1)
剥离版本 - NON UDF 这可以注入你的SQL
Declare @startdate Date ='1/1/2014' -- user supplied value
Declare @enddate Date = '6/1/2014' -- user supplied value
Declare @DateFrom Date = cast('2013-'+cast(month(@StartDate) as varchar(10))+'-'+cast(Day(@StartDate) as varchar(10)) as date)
Declare @DateTo Date = cast(cast(Year(GetDate()) as varchar(10))+'-'+cast(month(@enddate) as varchar(10))+'-'+cast(Day(@enddate) as varchar(10)) as date)
Declare @Incr int = DateDiff(MM,@startdate,@enddate) -- made to be dynamic based on the user supplied dates
Declare @DateRange Table (DateR1 date,DateR2 Date)
;with DateTable As (
Select DateFrom = @DateFrom
Union All
Select DateAdd(YY, 1, df.dateFrom)
From DateTable DF
Where DF.DateFrom < @DateTo
)
Insert into @DateRange(DateR1,DateR2) Select DateR1=DateFrom,DateR2=DateAdd(MM,@Incr,DateFrom) From DateTable option (maxrecursion 32767)
Select * from @DateRange
答案 1 :(得分:3)
每当您想要生成数字上不同的内容列表(递增等)时,请考虑使用Tally table(数字表)。生成日期是计数表的一个很好的应用程序:
declare @startDate date = '20160101'
declare @endDate date = '20160601'
select N
, dateadd(year, (N - 1) * -1, @startDate) as StartDate
, dateadd(year, (N - 1) * -1, @endDate) as EndDate
from tally -- Follow the link above for info on how to create this table
where N <= 4
order by N desc
结果:
N StartDate EndDate
4 2013-01-01 2013-06-01
3 2014-01-01 2014-06-01
2 2015-01-01 2015-06-01
1 2016-01-01 2016-06-01
在查询中使用计数表进行计算通常比循环,游标或动态SQL更有效。在这种情况下,与其他答案相比,我说它也更容易编程和维护。
在看到其他几个答案之后,我必须说我强烈建议您不创建大量编号变量来保存这些值。在其他可能使用数组或列表或其他数据结构的语言中,这通常是糟糕的风格,更不用说设置的SQL以及操作和存储它们的方法是语言本身的基础。
也许我没有看到您的特定用例,但即使您使用代码创建这些编号的变量,您也必须编写 more 代码来实际调用这些变量在任何后续的逻辑或计算中。
答案 2 :(得分:2)
首先,创建一个这样的数字表。
declare @numbers table(n int)
insert into @Numbers(N)
select top 1000 row_number() over(order by t1.number) as N
from master..spt_values t1
cross join master..spt_values t2
然后创建这样的日期
declare @iniDate date
declare @endDate date
delcare @limitDate date
set @iniDate='20160101'
set @enddate='20160106'
set @limitDate ='20130101'
select dateadd(yy,-1*(n-1),@inidate), dateadd(yy,-1*(n-1),@enddate)
from @numbers where (n-1)<=datediff(yy, @limitDate, @inidate)
编辑: 在新请求之后,试试这个:
declare @iniDate date
declare @endDate date
declare @iniLimitDate date
declare @endLimitDate date
set @iniDate='20140201'
set @endDate='20140206'
set @iniLimitDate ='20130101'
set @endLimitDate ='20161231'
select datefromparts(year(@iniLimitDate)+n-1,month(@iniDate), day(@iniDate))
,datefromparts(year(@iniLimitDate)+n-1,month(@endDate), day(@endDate))
from @numbers
where year(@iniLimitDate)+n-1<=year(@endlimitdate)
and year(@iniLimitDate)+n-1<>year(@enddate)
注意:需要修复2月29日
答案 3 :(得分:1)
这样的事情对你有用吗?它使用动态SQL来构建查询。我不知道你的日期格式,但我使用强制转换来从标准的getDate()函数中切断时间部分以防万一。
DECLARE @iter int = 1
Declare @SQL VARCHAR(MAX)
WHILE @iter<11
BEGIN
SET @SQL = ISNULL(@SQL,'') + ' DECLARE @newdate'+ CAST(@iter AS VARCHAR) + ' DATE = ' + CAST(CAST(GETDATE() AS DATE) AS VARCHAR) + ' '
PRINT (@SQL)
SET @iter = @iter + 1
END
SET @SQL = @SQL + ' SELECT * FROM blah'
EXEC @SQL
答案 4 :(得分:1)
John比我在这里的简单示例有更好的解决方案,但是这个解决方案并不需要单独的UDF。如果您没有权限使用这些或某些内容。
DECLARE @startDate DATETIME, @endDate DATETIME, @tmpStartDate DATETIME, @tmpEndDate DATETIME
SET @startDate = '1/1/2016'
SET @endDate = '6/1/2016'
SET @tmpStartDate = @startDate
SET @tmpEndDate = @endDate
DECLARE @dateTbl TABLE (startDate DATETIME, endDate DATETIME)
WHILE (DATEPART(YEAR, @tmpStartDate) >= 2013)
BEGIN
INSERT INTO @dateTbl VALUES (@tmpStartDate, @tmpEndDate)
SET @tmpStartDate = DATEADD(year, -1, @tmpStartDate)
SET @tmpEndDate = DATEADD(year, -1, @tmpStartDate)
END
SELECT * FROM @dateTbl
答案 5 :(得分:1)
提到的其他方法对于您正在尝试的方法要好得多,但在回答问题方面&#34;有没有办法迭代地DECLARE变量?&#34;,你可以做类似我的事情下面使用动态SQL。基本上,您将使用包含声明语句的循环创建一个字符串。然后,您将创建一个额外的字符串(或字符串)来使用它们。在这个例子中,我只是创建变量并将它们设置为今天的日期。然后我选择每个变量。
DECLARE @iter INT = 1, @SQL VARCHAR(MAX) = '', @MoreSQL VARCHAR(MAX) = '';
WHILE @iter < 11
BEGIN
SET @SQL += 'DECLARE @NewDate' + CAST(@iter AS VARCHAR(2)) + ' DATE = GETDATE() '
SET @iter += 1
END
SET @iter = 1
WHILE @iter < 11
BEGIN
SET @MoreSQL += 'SELECT @NewDate' + CAST(@iter AS VARCHAR(2)) + ' '
SET @iter += 1
END
SET @SQL += @MoreSQL
EXEC (@SQL)
答案 6 :(得分:0)
仅获得过去4年的开始/结束范围:
DECLARE @START DATETIME, @END DATETIME
SET @START='2016-01-01'
SET @END='2016-06-01'
DECLARE @DATES TABLE (STARTDATE DATETIME, ENDDATE DATETIME)
INSERT INTO @DATES (STARTDATE, ENDDATE)
SELECT @START,@END UNION
SELECT DATEADD(YY,-1,@START),DATEADD(YY,-1,@END) UNION
SELECT DATEADD(YY,-2,@START),DATEADD(YY,-2,@END) UNION
SELECT DATEADD(YY,-3,@START),DATEADD(YY,-3,@END)
SELECT * FROM @DATES ORDER BY STARTDATE
获取介于两者之间的所有日期:
DECLARE @START DATETIME, @END DATETIME
SET @START='2016-01-01'
SET @END='2016-06-01'
DECLARE @CURDATE DATETIME
DECLARE @DATES TABLE (DATEVAL DATETIME)
SET @CURDATE=@START
WHILE @CURDATE<=@END
BEGIN
INSERT INTO @DATES (DATEVAL)
SELECT @CURDATE UNION
SELECT DATEADD(YY,-1,@CURDATE) UNION
SELECT DATEADD(YY,-2,@CURDATE) UNION
SELECT DATEADD(YY,-3,@CURDATE)
SET @CURDATE=DATEADD(DD,1,@CURDATE)
END
SELECT * FROM @DATES ORDER BY DATEVAL
从@START到2013年的所有年份......
DECLARE @START DATETIME, @END DATETIME
SET @START='2016-01-01'
SET @END='2016-06-01'
DECLARE @DATES TABLE (STARTDATE DATETIME, ENDDATE DATETIME)
DECLARE @CURYEAR INT
SET @CURYEAR=YEAR(@START)
WHILE @CURYEAR>= 2013
BEGIN
INSERT INTO @DATES (STARTDATE, ENDDATE)
SELECT @START,@END
SET @START = DATEADD(YY,-1,@START)
SET @END = DATEADD(YY,-1,@END)
SET @CURYEAR=YEAR(@START)
END
SELECT * FROM @DATES ORDER BY STARTDATE