簡體   English   中英

SQL Server 2008 - While循環的替代方案

[英]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 TableCROSS 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM