[英]SQL Server 2008 - Alternatives to While Loop
我有一個在WHILE循環中運行的INSERT語句。 在WHILE循環的每次迭代中,調用一些函數,並將日期變量作為參數傳遞。 這些日期變量在循環的每次迭代中增加一天。
這是一個精簡的例子:
-- Start and End Date
DECLARE
@StartDate DATE = '20170101'
,@EndDate DATE = '20170110'
-- Initialise Loop variables to Start Date
DECLARE
@InsertDate DATE = @StartDate
,@NextDate DATE = @StartDate
-- Loop for All Dates
WHILE (@InsertDate <> @EndDate)
BEGIN
-- Gather Data to Insert
INSERT INTO tblCombinedData
SELECT
a.SomeString
,b.SomeNumber
,dbo.fnDoSomeStuff(a.AKey,@InsertDate,@NextDate)
,dbo.fnDoSomeMoreStuff(b.AKey,@InsertDate,@NextDate)
FROM
tblATable a
INNER JOIN tblAnotherTable b
ON a.ID = b.ID
-- Move to next Set of Dates
SET @InsertDate = DATEADD(DAY,1,@InsertDate)
SET @NextDate = DATEADD(DAY,1,@InsertDate)
END
有沒有更有效的方法來實現這個組合插入? (可能通過CTE?)謝謝。
注意:(SQL Server 2008 R2)
日歷CTE,有人嗎?
with CTE as
(
select @startdate as InsertDay
union all
select dateadd(day, 1, @startdate)
from CTE
where @startdate < @enddate
)
insert into tblCombinedData
select a1.stuff, fn(a1.stuff2, InsertDay, dateadd(day,1,InsertDay))
from CTE
cross join
(
select stuff, stuff2
from tab1
inner join tab2
on tab1.thing = tab2.thing
)
其他方式....
declare @table1 table (dt datetime)
declare @table2 table (notDT char)
insert into @table1 (dt) values
('1/1/2017'),
('1/2/2017'),
('1/3/2017'),
('1/4/2017')
insert into @table2 (notDT) values
('a'),
('b'),
('c')
;with t2 as(
select
*,
ROW_NUMBER() over (order by (select null)) as rn
from @table2),
t1 as(
select
*,
ROW_NUMBER() over (order by dt) as rn
from @table1)
select
t2.notDT,
t1.dt
from
t2
inner join t1 on t1.rn = t2.rn
您可以使用特殊的Tally Table與CROSS APPLY一起使用
Declare @Date1 date = '20170101'
Declare @Date2 date = '20170110'
-- Insert Into tblCombinedData
Select B.*
From (Select Top (DateDiff(DD,@Date1,@Date2)+1) D=DateAdd(DD,-1+Row_Number() Over (Order By Number),@Date1) From master..spt_values) DT
Cross Apply (
SELECT a.SomeString
,b.SomeNumber
,dbo.fnDoSomeStuff(a.AKey,DT.D,DT.D) --<< Notice DT.D
,dbo.fnDoSomeMoreStuff(b.AKey,DT.D,DT.D) --<< Notice DT.D
FROM tblATable a
INNER JOIN tblAnotherTable b ON a.ID = b.ID
) B
如果它有助於可視化,ad-hoc計數表就像這樣
D
2017-01-01
2017-01-02
2017-01-03
2017-01-04
2017-01-05
2017-01-06
2017-01-07
2017-01-08
2017-01-09
2017-01-10
嘗試使用Recursive CTE
:
;WITH CTE
AS (
SELECT @StartDate AS StartDate, DATEADD(DAY,1,@StartDate) AS NextDate
UNION ALL
SELECT DATEADD(DAY,1,StartDate) AS StartDate, DATEADD(DAY,1,NextDate) AS NextDate
FROM CTE
WHERE DATEADD(DAY,1,NextDate) <= @EndDate
)
INSERT INTO tblCombinedData
SELECT
a.SomeString
,b.SomeNumber
,dbo.fnDoSomeStuff(a.AKey, CTE.StartDate, CTE.NextDate)
,dbo.fnDoSomeMoreStuff(b.AKey, CTE.StartDate, CTE.NextDate)
FROM tblATable a
INNER JOIN tblAnotherTable b ON a.ID = b.ID
CROSS JOIN CTE
使用Calendar表可以更好地處理這個問題,但是如果你必須使用某些東西來按需生成日期,那么這樣做:
declare @fromdate date = '20170101';
declare @thrudate date = '20170110';
;with dates as (
select top (datediff(day, @fromdate, @thrudate)+1)
InsertDate=convert(date,dateadd(day,row_number() over(order by (select 1))-1,@fromdate))
, NextDate =convert(date,dateadd(day,row_number() over(order by (select 1)) ,@fromdate))
from master..spt_values a cross join master..spt_values b
order by 1
)
insert into tblCombinedData
select
a.SomeString
, b.SomeNumber
, dbo.fnDoSomeStuff(a.akey,d.InsertDate,d.NextDate)
, dbo.fnDoSomeMoreStuff(b.akey,d.InsertDate,d.NextDate)
from tblatable a
inner join tblAnotherTable b
on a.id = b.id
cross join dates d;
這不使用遞歸 公用表表達式 (cte),只是常規cte。 使用遞歸 cte生成序列是生成沒有循環的集合或序列的最慢方法。
數字和日歷表參考:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.