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

时间:2017-03-15 15:26:58

标签: sql sql-server sql-server-2008 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)

5 个答案:

答案 0 :(得分:0)

日历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
)

答案 1 :(得分:0)

另一种方式......

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

答案 2 :(得分:0)

您可以使用 ad-hoc 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

答案 3 :(得分:0)

使用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

答案 4 :(得分:0)

使用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;

这不使用递归 common table expression(cte),只是一个普通的cte。使用递归 cte生成序列是生成没有循环的集合或序列的最慢方法。

数字和日历表参考: