2012-04-24 65 views
47

我有以下SQL查詢:SQL Server的每個循環

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 3/1/2010 2010/4/1 2010年5月1日

我希望這可以返回數據作爲一個結果集,而不是多個結果集,所以我可能需要在查詢結束時使用某種聯合,所以每次迭代循環聯合到下一個。

編輯

我有一個接受「最新」參數大型查詢,我需要運行24次,用特定的日期,我需要能夠提供每次(這些日期將是動態的)我想避免重複我的查詢24次與聯盟所有人加入他們,就好像我需要回來並添加額外的列這將是非常耗時。

+9

你能解釋爲什麼你需要這樣做嗎?當你需要tSQL中的循環結構時,有95%的時間你可能做錯了。 – JohnFx 2012-04-24 14:53:11

+2

爲什麼不創建一個表格,您可以在其中填充要運行的日期。與通過硬編碼的常量值進行查看相比,幾乎可以肯定有更好的方法來做到這一點。 – JohnFx 2012-04-24 14:57:12

+0

您示例中的日期是按月順序排列的。這是一個規則,還是你需要能夠運行一組任意日期?是否有理由不能編輯大型查詢來取日期範圍或日期集而不是單一日期?如果你絕對需要通過迭代(針對上面給出的好建議),那麼你可能需要考慮使用遊標。 – JAQFrost 2012-04-24 22:36:58

回答

51

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 
+4

'i'的最大步數限制爲100,這等於最大遞歸限制。嘗試'...從CTE我<= 101'或增加遞歸遞增限制通過'OPTION(MAXRECURSION 500)添加' – guneysus 2016-07-11 12:23:29

26

這是一個帶表變量的選項:

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,這可能可以做另一種(更有效的)方式。

+0

我需要循環日期而不是整數,請參閱編輯的問題。 WHILE循環會與日期一起工作嗎? – JsonStatham 2012-04-24 15:12:53

+0

@SelectDistinct - 是的,它應該工作得很好。我改變了我的答案返回日期,而不是整數 – Lamak 2012-04-24 15:22:57

+1

馬克班尼斯特的答案是代碼少,效率更高。沒有理由爲此類使用while循環。 – Sorpigal 2012-04-24 16:41:25

13

你可以使用一個變量表,如下所示:

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 
+0

+1這工作得很好。 – 2013-05-22 14:58:03

6

這種取決於你想要做的結果是什麼。如果您剛好在數字之後,則基於集合的選項將爲numbers table - 這適用於各種各樣的事情。

對於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) 
+0

有趣的是,你認爲這是一個「基於集合的選項」(單詞「RECURSION」有點放棄!) – onedaywhen 2012-04-25 08:17:24

+0

@onedaywhen - 那裏沒有矛盾。遞歸CTE *是*基於集合的。將定位成員(SELECT 1)設置爲S [0],然後將UNION ALL'n用更多的集合(SELECT 1 + N FROM S [n-1])直到遇到空集合。結果是集合S [0]到S [n]的聯合。這就是說 - 我個人更喜歡物理表,因爲它更高效。 – 2012-04-25 13:52:32

+0

[Joe Celko對此事的看法](http://www.simple-talk.com/sql/t-sql-programming/procedural,-semi-procedural-and-claclarative-programing-part-ii/):「它使得半程序程序員使用[遞歸] CTE感覺很好......但遞歸實際上是一種程序技術,它也是昂貴的,因爲它實際上是一個光標下的光標「 - 我不是說他是正確,但表明立場並不像你想象的那樣明確。不要批評你的評論。正如我所說,我覺得它很有趣,沒有堅持自己的主題強烈的意見:) – onedaywhen 2012-04-26 07:26:37

5
declare @counter as int 
set @counter = 0 
declare @date as varchar(50) 
set @date = cast([email protected] as varchar)+'/01/2013' 
while(@counter < 12) 
begin 
select cast([email protected] as varchar)+'/01/2013' as date 
set @counter = @counter + 1 
end 
1
[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] 
1

當然,一個老問題。但我有一個簡單的解決方案,無需循環,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