March 26, 2010 at 6:40 am
thanks Paul; awesome performance on that one; i added that to my toolbox; excellent solution.
Lowell
March 26, 2010 at 6:49 am
Lowell (3/26/2010)
thanks Paul; awesome performance on that one; i added that to my toolbox; excellent solution.
I should point out that it is rather specifically optimized for the test data presented in this thread. The tally solution is likely much more general. In particular, you would need to add an OPTION (MAXRECURSION 0) statement to the final SELECT if any of the ranges exceed 100. The recursive method is not well suited to large ranges, due to inefficient recursive plan elements.
March 26, 2010 at 7:15 am
LOL Awesome code regardless...
Both of these are in my toolbox. Great stuff!
<hr noshade size=1 width=250 color=#BBC8E5> Regards,Jeffery Williams http://www.linkedin.com/in/jwilliamsoh
March 26, 2010 at 11:38 am
Nice solution Paul. As another variation, I have adapted it slightly to a self-contained CTE block without the table function. You may recognize the final Listed CTE as the same as yours. BTW better luck in the 2nd Test!
SET STATISTICS IO, TIME ON
;
WITH
cteSample AS
(
SELECT '44100-44110, 44150' AS bulkcolumn UNION ALL
SELECT '44115, 44125, 44157' UNION ALL
SELECT '44250-44350, 44128, 44524-44555, 44112, 52144'
)
,
cteSplit
AS
(
SELECT item FROM cteSample
CROSS APPLY
(
SELECT SUBSTRING(bulkcolumn + ',', N, CHARINDEX(',', bulkcolumn + ',', N) - N) AS item
FROM master.dbo.TALLY
WHERE N < LEN(bulkcolumn) + 2 AND SUBSTRING(',' + bulkcolumn + ',', N, 1) = ','
) AS Z
)
,
Listed
AS
(
SELECT value =
CASE WHEN CHARINDEX('-', S.item) = 0 THEN CONVERT(INT, S.item)
ELSE CONVERT(INT, LEFT(S.item, CHARINDEX('-', S.item) - 1)) END,
max_value =
CASE WHEN CHARINDEX('-', S.item) = 0 THEN 0
ELSE CONVERT(INT, SUBSTRING(S.item, CHARINDEX('-', S.item) + 1, 50)) END
FROM cteSplit S
UNION ALL
SELECT L.value + 1,
L.max_value
FROM Listed L
WHERE L.max_value > L.value
)
SELECT value FROM Listed
;
SET STATISTICS IO, TIME OFF
;
--(151 row(s) affected)
--Table 'Worktable'. Scan count 2, logical reads 890, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Table 'TALLY'. Scan count 3, logical reads 12, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--
--SQL Server Execution Times:
-- CPU time = 0 ms, elapsed time = 3 ms.
March 26, 2010 at 11:58 am
steve-893342 (3/26/2010)
Nice solution Paul.
Thanks, Steve.
As another variation, I have adapted it slightly to a self-contained CTE block without the table function.
Ok. You did notice that it was an in-line TVF though, right? It gets expanded into the query plan of the caller before optimization just like a parameterized view would. Doesn't really matter though, I guess.
BTW better luck in the 2nd Test!
Thank you. It would be nice to beat the Aussies again. Not many people have managed that this summer.
March 26, 2010 at 12:07 pm
Yes it would. Maybe Vettori can produce something special in his 100th Test.
Doing all right so far with 4-36 and running out Ponting to boot!
March 27, 2010 at 4:36 am
Sorry folks, can't leave this one alone. I have come up with another variation, which like Wayne's, uses the TALLY table to do both the split and the range evaluation. Obviously it relies on the numbers in the range not exceeding the current 1 million limit of the TALLY table.
SET STATISTICS IO, TIME ON
;
WITH
cteSample AS
(
SELECT '44100-44110, 44150' AS bulkcolumn UNION ALL
SELECT '44115, 44125, 44157' UNION ALL
SELECT '44250-44350, 44128, 44524-44555, 44112, 52144'
)
,
cteSplit
AS
(
SELECT item FROM cteSample
CROSS APPLY
(
SELECT SUBSTRING(bulkcolumn + ',', N, CHARINDEX(',', bulkcolumn + ',', N) - N) AS item
FROM master.dbo.TALLY
WHERE N < LEN(bulkcolumn) + 2 AND SUBSTRING(',' + bulkcolumn + ',', N, 1) = ','
) AS Z
)
SELECT N AS value FROM cteSplit
CROSS APPLY
(
SELECT N from master.dbo.TALLY WHERE N BETWEEN LEFT(item, CHARINDEX('-', item) - 1)
AND REVERSE(LEFT(REVERSE(item), CHARINDEX('-', REVERSE(item)) - 1))
) AS Z
WHERE CHARINDEX('-', item) > 0
UNION ALL SELECT item from cteSplit
WHERE CHARINDEX('-', item) = 0
;
SET STATISTICS IO, TIME OFF
;
--(151 row(s) affected)
--
--Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Table 'TALLY'. Scan count 9, logical reads 45, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--
--SQL Server Execution Times:
-- CPU time = 0 ms, elapsed time = 2 ms.
March 27, 2010 at 1:40 pm
Heh... absolutely remarkable. On a bit of a meloncholy note, it's amazing how things have changed in the last 7 or so years on this fine forum. "I remember when" the mantra for such problems was "Oh... for that, you need a cursor" and I had to, yet again, explain what a Tally table was and how it worked. Well done, Gents, and thanks for passing it forward.
--Jeff Moden
Change is inevitable... Change for the better is not.
March 27, 2010 at 10:38 pm
steve-893342 (3/27/2010)
Sorry folks, can't leave this one alone. I have come up with another variation, which like Wayne's, uses the TALLY table to do both the split and the range evaluation. Obviously it relies on the numbers in the range not exceeding the current 1 million limit of the TALLY table.
SET STATISTICS IO, TIME ON
;
WITH
cteSample AS
(
SELECT '44100-44110, 44150' AS bulkcolumn UNION ALL
SELECT '44115, 44125, 44157' UNION ALL
SELECT '44250-44350, 44128, 44524-44555, 44112, 52144'
)
,
cteSplit
AS
(
SELECT item FROM cteSample
CROSS APPLY
(
SELECT SUBSTRING(bulkcolumn + ',', N, CHARINDEX(',', bulkcolumn + ',', N) - N) AS item
FROM master.dbo.TALLY
WHERE N < LEN(bulkcolumn) + 2 AND SUBSTRING(',' + bulkcolumn + ',', N, 1) = ','
) AS Z
)
SELECT N AS value FROM cteSplit
CROSS APPLY
(
SELECT N from master.dbo.TALLY WHERE N BETWEEN LEFT(item, CHARINDEX('-', item) - 1)
AND REVERSE(LEFT(REVERSE(item), CHARINDEX('-', REVERSE(item)) - 1))
) AS Z
WHERE CHARINDEX('-', item) > 0
UNION ALL SELECT item from cteSplit
WHERE CHARINDEX('-', item) = 0
;
SET STATISTICS IO, TIME OFF
;
--(151 row(s) affected)
--
--Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--Table 'TALLY'. Scan count 9, logical reads 45, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
--
--SQL Server Execution Times:
-- CPU time = 0 ms, elapsed time = 2 ms.
Steve - this is fabulous! I have got to learn a lot more about cross apply... I see it being used more and more with some pretty awesome performance enhancements.
Wayne
Microsoft Certified Master: SQL Server 2008
Author - SQL Server T-SQL Recipes
March 27, 2010 at 10:47 pm
The article I wrote on APPLY is in the queue for publication.
March 28, 2010 at 11:40 am
Paul White NZ (3/27/2010)
The article I wrote on APPLY is in the queue for publication.
I'm ready for it! Judging solely by some of the posts where you have utilized it, I fully expect this to be one awesome article.
Wayne
Microsoft Certified Master: SQL Server 2008
Author - SQL Server T-SQL Recipes
March 28, 2010 at 11:54 pm
WayneS (3/28/2010)
Paul White NZ (3/27/2010)
The article I wrote on APPLY is in the queue for publication.I'm ready for it! Judging solely by some of the posts where you have utilized it, I fully expect this to be one awesome article.
Hmm..so no pressure then 😉
I have asked Steve for a publication date.
March 29, 2010 at 6:16 am
Nice and fast solutions.
Here's a similar thread ....
http://www.sqlservercentral.com/Forums/Topic699260-1291-1.aspx
Johan
Learn to play, play to learn !
Dont drive faster than your guardian angel can fly ...
but keeping both feet on the ground wont get you anywhere :w00t:
- How to post Performance Problems
- How to post data/code to get the best help[/url]
- How to prevent a sore throat after hours of presenting ppt
press F1 for solution, press shift+F1 for urgent solution 😀
Need a bit of Powershell? How about this
Who am I ? Sometimes this is me but most of the time this is me
Viewing 13 posts - 16 through 27 (of 27 total)
You must be logged in to reply to this topic. Login to reply