create while loop with cte
If you need table:
;WITH Sec(Number) AS
(
SELECT 0 AS Number
UNION ALL
SELECT Number + 1
FROM Sec
WHERE Number < 884
)
SELECT * FROM Sec
OPTION(MAXRECURSION 0)
If you need one string:
;WITH Sec(Number) AS
(
SELECT 0 AS Number
UNION ALL
SELECT Number + 1
FROM Sec
WHERE Number < 884
)
SELECT STUFF(a.[Str], 1, 1, '')
FROM
(
SELECT (SELECT ',' + CAST(Number AS NVARCHAR(3))
FROM Sec
FOR XML PATH(''), TYPE
).value('.','varchar(max)') AS [Str]
) AS a
OPTION(MAXRECURSION 0)
How to re write while loop using cte
I don't know, if I fully got the logic, but this might help to get you running:
USE master;
GO
CREATE DATABASE TestDB
GO
USE TestDB;
GO
CREATE TABLE dbo.Episode ([ID] INT, [Start] DateTime, [End] DateTime, [Type] varchar(1), [User] INT)
INSERT INTO [dbo].Episode ([ID], [Start], [End], [Type],[User])
VALUES
(1, '2018-07-01 10:00', '2018-07-02 14:00', 'A',10),
(2, '2018-07-05 6:00', '2018-07-06 13:00', 'A',11),
(3, '2018-07-03 9:00', '2018-07-04 8:00', 'B',10),
(4, '2018-07-02 15:00', '2018-07-03 7:00', 'B',12),
(5, '2018-07-01 1:00', '2018-07-02 8:00', 'C',13),
(6, '2018-07-01 6:00', '2018-07-01 8:00', 'D',11)
CREATE TABLE dbo.[Event] ([ID] INT, [Date] DateTime, [Type] varchar(1), [User] INT)
INSERT INTO [dbo].[Event] ([ID], [Date], [Type],[User])
VALUES
(0, '2018-07-01 12:00', 'A',10),
(0, '2018-07-05 15:00', 'A',11),
(0, '2018-07-03 13:00', 'C',10),
(0, '2018-07-10 9:00', 'B',12),
(0, '2018-07-01 5:00', 'C',10),
(0, '2018-07-01 10:00', 'D',11)
GO
CREATE TABLE #EventList(Event Varchar(50), RN INT);
INSERT INTO #EventList VALUES ('A', 1),('B', 2),('C', 3),('D', 4),('E', 5),('F', 6);
WITH mathingEpisodes AS
(
SELECT ev.ID AS evID
,ev.[Date] AS evDate
,ev.[Type] AS evType
,ev.[User] AS evUser
,e1.RN AS evRN
,ep.ID AS epID
,ep.[Type] AS epType
,e2.RN AS epRN
FROM [Event] ev
LEFT JOIN Episode ep ON ev.[User]=ep.[User] AND ev.[Date] >= ep.[Start] AND ev.[Date] < ep.[End]
LEFT JOIN #EventList e1 ON ev.[Type]=e1.[Event]
LEFT JOIN #EventList e2 ON ep.[Type]=e2.[Event]
)
SELECT COALESCE(epID,Closest.ID) AS FittingEpisodeID
,me.evDate
,evType
,evUser
FROM mathingEpisodes me
OUTER APPLY(SELECT TOP 1 *
FROM Episode ep
CROSS APPLY(SELECT ABS(DATEDIFF(SECOND,me.evDate,ep.[Start])) AS DiffToStart
,ABS(DATEDIFF(SECOND,me.evDate,ep.[End])) AS DiffToEnd) Diffs
CROSS APPLY(SELECT CASE WHEN DiffToStart<DiffToEnd THEN DiffToStart ELSE DiffToEnd END AS Smaller) Diffs2
WHERE ep.[User] = me.evUser
AND me.epID IS NULL
ORDER BY Diffs2.Smaller
) Closest
ORDER BY evDate;
GO
USE master;
GO
DROP DATABASE TestDB;
GO
DROP TABLE #EventList
GO
The result
1 2018-01-07 05:00:00.000 C 10
6 2018-01-07 10:00:00.000 D 11
1 2018-01-07 12:00:00.000 A 10
3 2018-03-07 13:00:00.000 C 10
2 2018-05-07 15:00:00.000 A 11
4 2018-10-07 09:00:00.000 B 12
Some explanation
In the first cte I try to find fitting episodes (same user and date within range).
The second cte will compute the closest Episode for the same user in all cases, where the first cte did not succeed.
The only difference for this sample is the event for userId=12. My logic will bind this to the closest episode of this user (ID=4), while your expected output shows a zero in this place.
Anyway, my solution is fully set-based, therefore faster than a loop, and should be rather close to your needs. Try to adapt it...
UPDATE Some more thoughts...
I did not get the ghist of your #EventList... I bound the results into the set (you can make it visible by using SELECT *
instead of the explicit column list. But this is - assumably - not what you meant...
Common Table Expression in a SQL WHILE loop?
You can't do that. The CTE's scope is only the for the next query. It is effectively actually just a part of the query it precedes. Just like an inline view (sub-query) is part of a larger query.
In your case you'd need to go back to good old temp tables, table variables, etc.
Related Topics
When Should I Nest Pl/SQL Begin...End Blocks
Rails Order by Association Field
Cycle Detection with Recursive Subquery Factoring
Select Statement in Sqlite Recognizing Row Number
Select The First Row in a Join of Two Tables in One Statement
Writing a Function in SQL to Loop Through a Date Range in a Udf
Acts-As-Taggable-On Find All Tags by Context
Reshape from Wide to Long in Big Query (Standard Sql)
Oracle Pls-00363: Expression '' Cannot Be Used as an Assignment Target
Oracle 11G - How to Optimize Slow Parallel Insert Select
Simple, Fast SQL Queries for Flat Files
How to Avoid SQL Query Timeout
Are There Any Limits on Length of String in MySQL
Sql: How to Order Null and Empty Entries to The Front in an Orderby
Sql Server Store Multiple Values in SQL Variable
How to Multiply All Values Within a Column with SQL Like Sum()
How to Increase Dbms_Output Buffer
How to Select Only Row with Max Sequence Without Using a Subquery