SQL Server FOR EACH循环

我有以下SQL查询:

DECLARE @MyVar datetime = '1/1/2010'    
SELECT @MyVar

这自然会返回“ 1/1/2010”。

我要做的是列出日期,例如:

1/1/2010
2/1/2010
3/1/2010
4/1/2010
5/1/2010

然后,我想通过数字逐个运行SQL查询。

类似于(伪代码):

List = 1/1/2010,2/1/2010,3/1/2010,4/1/2010,5/1/2010

For each x in List
do
  DECLARE @MyVar datetime = x

  SELECT @MyVar

所以这将返回:

1/1/2010     2010年2月1日     2010年3月1日     2010年4月1日     5/1/2010

我希望这将数据作为一个结果集而不是多个结果集返回,因此我可能需要在查询的末尾使用某种类型的并集,以便将循环并集的每次迭代都移至下一个。

编辑

我有一个接受“ to date”参数的大型查询,我需要运行24次,每次都有一个我需要提供的特定日期(这些日期将是动态的),我想避免 将工会全都加入其中,重复24次查询,好像我需要返回并添加其他列一样,这将非常耗时。

JsonStatham asked 2019-11-08T09:59:34Z
7个解决方案
59 votes

SQL主要是一种面向集合的语言-在其中使用循环通常是个坏主意。

在这种情况下,使用递归CTE可以达到类似的结果:

with cte as
(select 1 i union all
 select i+1 i from cte where i < 5)
select dateadd(d, i-1, '2010-01-01') from cte
answered 2019-11-08T09:59:57Z
30 votes

这是一个带有表变量的选项:

DECLARE @MyVar TABLE(Val DATETIME)
DECLARE @I INT, @StartDate DATETIME
SET @I = 1
SET @StartDate = '20100101'

WHILE @I <= 5
BEGIN
    INSERT INTO @MyVar(Val)
    VALUES(@StartDate)

    SET @StartDate = DATEADD(DAY,1,@StartDate)
    SET @I = @I + 1
END
SELECT *
FROM @MyVar

您可以对临时表执行相同的操作:

CREATE TABLE #MyVar(Val DATETIME)
DECLARE @I INT, @StartDate DATETIME
SET @I = 1
SET @StartDate = '20100101'

WHILE @I <= 5
BEGIN
    INSERT INTO #MyVar(Val)
    VALUES(@StartDate)

    SET @StartDate = DATEADD(DAY,1,@StartDate)
    SET @I = @I + 1
END
SELECT *
FROM #MyVar

您应该告诉我们您的主要目标是什么,就像@JohnFx所说的那样,这可以用另一种(更有效的)方法来完成。

Lamak answered 2019-11-08T10:00:33Z
14 votes

您可以使用变量表,如下所示:

declare @num int

set @num = 1

declare @results table ( val int )

while (@num < 6)
begin
  insert into @results ( val ) values ( @num )
  set @num = @num + 1
end

select val from @results
Steve Mayne answered 2019-11-08T10:00:56Z
6 votes

这种取决于您要如何处理结果。 如果您只是在数字后面,则基于集合的选项将是数字表-对于各种事情都很方便。

对于MSSQL 2005+,可以使用递归CTE内联生成数字表:

;WITH Numbers (N) AS (
    SELECT 1 UNION ALL
    SELECT 1 + N FROM Numbers WHERE N < 500 
)
SELECT N FROM Numbers
OPTION (MAXRECURSION 500)
Mark Brackett answered 2019-11-08T10:01:27Z
5 votes
declare @counter as int
set @counter = 0
declare @date as varchar(50)
set @date = cast(1+@counter as varchar)+'/01/2013'
while(@counter < 12)
begin 
select  cast(1+@counter as varchar)+'/01/2013' as date
set @counter = @counter + 1
end
younes answered 2019-11-08T10:01:44Z
2 votes

当然,这是一个老问题。 但是我有一个简单的解决方案,不需要循环,CTE,表变量等。

DECLARE @MyVar datetime = '1/1/2010'    
SELECT @MyVar

SELECT DATEADD (DD,NUMBER,@MyVar) 
FROM master.dbo.spt_values 
WHERE TYPE='P' AND NUMBER BETWEEN 0 AND 4 
ORDER BY NUMBER

注意:spt_values是Mircrosoft的未记录表格。 它具有每种类型的数字。 它不建议使用,因为它可以在任何新版本的sql server中删除,而无需事先提供信息,因为它没有记录。 但是,在上述某些情况下,我们可以将其用作快速解决方法。

Shakeer Mirza answered 2019-11-08T10:02:16Z
1 votes
[CREATE PROCEDURE [rat].[GetYear]

AS
BEGIN

-- variable for storing start date
Declare @StartYear as int
-- Variable for the End date 
Declare @EndYear as int 

-- Setting the value in strat Date
select @StartYear = Value from   rat.Configuration where Name = 'REPORT_START_YEAR'; 

-- Setting the End date 
select @EndYear = Value from   rat.Configuration where Name = 'REPORT_END_YEAR'; 


-- Creating Tem table 
    with [Years] as
    (
        --Selecting the Year
        select @StartYear [Year] 
        --doing Union 
        union all
         -- doing the loop in Years table 
         select Year+1 Year from [Years] where Year < @EndYear
     )
    --Selecting the Year table 
selec]
Soner Gönül answered 2019-11-08T10:02:34Z
translate from https://stackoverflow.com:/questions/10300414/sql-server-for-each-loop