Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2008 Forums
 Transact-SQL (2008)
 Loop

Author  Topic 

ugh3012
Yak Posting Veteran

62 Posts

Posted - 2013-06-26 : 14:21:15
What is the best way to loop through temp tables? I need to find gap in dates from one row to the next row. I just don’t see how I can do straight query except to loop through it.

James K
Master Smack Fu Yak Hacker

3873 Posts

Posted - 2013-06-26 : 14:30:58
You can do this without loops. See a simple example below. If you post more details on the problem you are trying to solve, people on this forum should be able to help. Loops are often very slow compared to set-based queries such as the one shown below
CREATE TABLE #tmp(Dt DATETIME NOT NULL PRIMARY KEY CLUSTERED);

INSERT INTO #tmp VALUES ('20130101'),('20130102'),('20130104'),('20130105'),('20130106'),('20130109');

SELECT
a.Dt AS [NextDate(s) Missing]
FROM
#tmp a
LEFT JOIN #tmp b ON
a.Dt = b.Dt-1
WHERE
b.Dt IS NULL

DROP TABLE #tmp;
Go to Top of Page

ugh3012
Yak Posting Veteran

62 Posts

Posted - 2013-06-26 : 15:01:26


What I need to do is to get the difference in number of days from end date to start date from the next record with the same ID. See example below. ID 52 has a difference of one day. The second record is deleted from the temp table. ID 54 has 32 days in difference (anything over 1 day is a gap). Both records for ID 54 will stay in the temp table.



Raw Data

ID |Row |Start Date |End Date
0052 |1 |10/01/2012 |12/31/2012
0052 |2 |01/01/2013 |12/31/2013
0054 |1 |10/01/2012 |12/31/2012
0054 |2 |02/01/2013 |12/31/2013

Result
ID |Row |Start Date |End Date
0052 |1 |01/01/2013 |12/31/2013
0054 |1 |10/01/2012 |12/31/2012
0054 |2 |02/01/2013 |12/31/2013
Go to Top of Page

James K
Master Smack Fu Yak Hacker

3873 Posts

Posted - 2013-06-26 : 15:13:11
If your data was like shown below, would you want to delete Row 2 and 3 for ID = 0052?
ID    |Row    |Start Date  |End Date
0052 |1 |10/01/2012 |12/31/2012
0052 |2 |01/01/2013 |12/31/2013
0052 |3 |01/01/2014 |12/31/2014
0054 |1 |10/01/2012 |12/31/2012
0054 |2 |02/01/2013 |12/31/2013
Go to Top of Page

ugh3012
Yak Posting Veteran

62 Posts

Posted - 2013-06-26 : 15:29:58
Yes, 2 and 3 will be deleted as there is no gap.
Go to Top of Page

James K
Master Smack Fu Yak Hacker

3873 Posts

Posted - 2013-06-27 : 08:31:18
Here are couple of different ways to get you started. I have done only minimal testing with the sample data here, so use it as a starting point rather than a final solution.
CREATE TABLE #tmp(ID INT, [Row] INT, [StartDate] DATETIME, endDate DATETIME);
INSERT INTO #tmp VALUES
(52,1,'10/1/2012','12/31/2012'),
(52,2,'1/1/2013','12/31/2013'),
(52,3,'1/1/2014','12/31/2014'),
(52,4,'1/2/2015','12/31/2015'),
(54,1,'10/1/2012','12/31/2012'),
(54,2,'2/1/2013','12/31/2013');

---ONE WAY

;WITH cte AS
(
SELECT
a.*,
COALESCE(b.hasNext,0) hasNext,
COALESCE(c.hasPrevious,0) AS hasPrevious
FROM
#tmp a
OUTER APPLY
(
SELECT CASE WHEN b.StartDate = DATEADD(dd,1,a.EndDate) THEN 1 ELSE 0 END AS hasNext
FROM #tmp b WHERE b.id = a.id AND a.row+1 = b.row
)b
OUTER APPLY
(
SELECT CASE WHEN a.StartDate = DATEADD(dd,1,b.EndDate) THEN 1 ELSE 0 END AS hasPrevious
FROM #tmp b WHERE b.id = a.id AND a.row = b.row+1
) c
)
SELECT
a.Id, a.Row, a.StartDate,
COALESCE(b.EndDate,a.EndDate) EndDate
FROM
cte a
OUTER APPLY
(
SELECT MIN(EndDate) EndDate FROM cte b
WHERE b.id = a.id AND b.hasNext = 0 AND b.EndDate >= a.EndDate
) b
WHERE
a.hasPrevious = 0;


--- ANOTHER WAY
;WITH cte AS
(
SELECT *,
endDate AS newEndDate,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY id,row) AS RN,
1 AS Lvl
FROM #tmp a
WHERE NOT EXISTS ( SELECT * FROM #tmp b WHERE b.id = a.ID
AND a.StartDate = DATEADD(dd,1,b.EndDate))

UNION ALL

SELECT t.*, t.EndDate AS NewEndDate, RN, lvl+1
FROM #tmp t
INNER JOIN cte c ON c.id = t.id AND c.row +1 = t.row
AND t.StartDate = DATEADD(dd,1,c.endDate)
),
cte2 AS
(
SELECT id,row,startdate, lvl,
MAX(newEndDate) OVER (PARTITION BY Id, RN) AS NewEndDate
FROM
cte
)
SELECT id,row,startdate, newenddate FROM cte2 WHERE lvl = 1
ORDER BY id, row;

drop table #tmp;
Go to Top of Page

ugh3012
Yak Posting Veteran

62 Posts

Posted - 2013-06-27 : 11:46:00
Thanks! I have so much to learn. I did not know anything about CTE and partition.
Go to Top of Page

James K
Master Smack Fu Yak Hacker

3873 Posts

Posted - 2013-06-27 : 11:57:03
You are very welcome. If you see incorrect results with your real data, reply back with consumable samples (like the one I created using the insert statements), and we can figure out the issues.
Go to Top of Page
   

- Advertisement -