我有一个在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)
答案 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生成序列是生成没有循环的集合或序列的最慢方法。
数字和日历表参考: