CTE looping query

2019-08-18 05:15发布

First I'll explain you the situation.

I want to transfer data from one table(View_Solidnet_Training) to another(OBJ_Availability). There is one problem: In the view there is a Start- and EndDate! In OBJ_Availability every date has one record. So one line in the view has multi lines in the other table.

I must work with CTE. So cursor is no option for me. The middle WITH runs perfect, but when I want to add an extra WITH to check if the ID isn't zero, it must change the variable @Start and @End to the new record in the view.

Sorry for my English, it isn't that good but I hope you understand the situation.

here is my code:

DECLARE @Start AS DATETIME;
DECLARE @End AS DATETIME;
SET @Start = '2013-04-09';
SET @End = '2013-04-11';
with cte1 as 
(

with cte2 as
(
select @Start as DateValue
union all

select DateValue + 1
from cte2
where DateValue + 1 <= @End
)
into OBJ_Availability  
select 34, DateValue, 'AM', 2, 'Test' from cte2
)
select * from cte1 where PK_Training_ID is not null;

Something like this, but I don't understand where it gets the information of the view. I never mentioned the name anywhere?

1条回答
混吃等死
2楼-- · 2019-08-18 06:03

I can not make comment yet, so I need to ask you few questions before answering.

1, how come the CTE's name is the same as the view's name? it should never work.

2, what do you mean by 'check if the ID isn't zero, it must change the variable @Start and @End to the new record in the view', I could not figure out why you need to do the null check

3, you sure you can use DateValue + 1 to get next date? should you be using DATEADD?

lastly, you cannot have a CTE inside a CTE, this is not going to work. Declare variable in CTE is not possible neither.

here is my best guest:

firstly, as you mentioned that your view has a startdate column and a enddate column,

so I assume there are StartDate and EndDate columns in the view, here is my sql:

DECLARE @start AS DATETIME
DECLARE @end AS DATETIME

SELECT @start = min(StartDate)
from View_Solidnet_Training 
where PK_Training_ID is not null

SELECT @end = max(EndDate) 
from View_Solidnet_Training 
where PK_Training_ID is not null

;with cte_dates as
(
    select @start DateValue
    union all
    select DateValue + 1
    from cte_dates
    where DateValue + 1 <= cast(@end as datetime)
)
into OBJ_Availability  
select v.PK_Training_ID, DateValue, 'AM', 2, 'Test' --columns from the view
from cte_dates cte
join View_Solidnet_Training v on v.StartDate < cte.DateValue and cte.DateValue < v.EndDate 
where v.PK_Training_ID is not null

the max() and min function figure out that newest and oldest date in the view

then the CTE cte_dates creates a list of dates from the @start to @end

then the join to the CTE will make records repeated within the range from StartDate to EndDate

hope this help

by the way, I do not have sql on my home pc, so I can check if

SELECT @start = min(StartDate)
from View_Solidnet_Training 
where PK_Training_ID is not null

runs or not, but you should get the idea

Use while instead of CTE:

DECLARE @start AS DATETIME
DECLARE @end AS DATETIME

SELECT @start = min(StartDate)
from View_Solidnet_Training 
where PK_Training_ID is not null

SELECT @end = max(EndDate) 
from View_Solidnet_Training 
where PK_Training_ID is not null

DECLARE @AllDates table
        (DateValue datetime)

DECLARE @dCounter datetime
SELECT @dCounter = @start

WHILE @dCounter <= @end
BEGIN
 INSERT INTO @AllDates VALUES (@dCounter)
 SELECT @dCounter=@dCounter+1 
END

insert into OBJ_Availability  
select v.PK_Training_ID, DateValue, 'AM', 2, 'Test' --columns from the view
from @AllDates d
join View_Solidnet_Training v on v.StartDate < d.DateValue and d.DateValue < v.EndDate 
where v.PK_Training_ID is not null

or you can even do

DECLARE @start AS DATETIME
DECLARE @end AS DATETIME

SELECT @start = min(StartDate)
from View_Solidnet_Training 
where PK_Training_ID is not null

SELECT @end = max(EndDate) 
from View_Solidnet_Training 
where PK_Training_ID is not null


DECLARE @dCounter datetime
SELECT @dCounter = @start

WHILE @dCounter <= @end
BEGIN

    insert into OBJ_Availability  
    select v.PK_Training_ID, DateValue, 'AM', 2, 'Test' --columns from the view
    from View_Solidnet_Training v
    where v on v.StartDate < @dCounter and @dCounter < v.EndDate and v.PK_Training_ID is not null

    SELECT @dCounter=@dCounter+1 
END
查看更多
登录 后发表回答