December 23, 2013 at 2:24 pm
I have a field in a table where the data varies in length. For some records, the length of the field is 8, for some records it's 20, for many records it's some number in between, NOT NECESSARILY divisible by four. I've been asked to change this data to xxxx.xxxx.xxxx. etc until I run out of numbers. So, for example if I have 12345678, I should change it to 1234.5678. If I have 12345, I should change it to 1234.5. 1234567890ABCDEFGH becomes 1234.5678.90AB.CDEF.GH. I can do this with a WHILE loop, but I try to stay away from looping in T-SQL and use set logic instead. I'm wondering, is there a way to do this that doesn't involve loops?
December 23, 2013 at 2:57 pm
check out this thread that has both a scalar and an inline table value function that resolves the same issue: splitting a string on a delimiter into new columns:
http://www.sqlservercentral.com/Forums/Topic1524275-3077-1.aspx#bm1524325
Lowell
December 23, 2013 at 3:03 pm
Thanks Lowell - this function would work if I had a delimiter, but I don't. I just need to break the string every 4 characters by inserting a period, until I get down to 4 characters or less, and then just add them.
December 23, 2013 at 3:04 pm
whoops after reading your post AFTER i posted, i see you really want to chop up the string based on a fixed length(ie 4 chars)
well, i know an example of that too! just change the length in this example and it should help as well:
http://www.sqlservercentral.com/Forums/Topic1525433-391-1.aspx#bm1525498
Lowell
December 23, 2013 at 3:09 pm
Ah ha! This looks good. It's almost 5:30 PM here, so I'm going to look at this tomorrow and let you know if it helps me, but it looks good. Thanks very much!
December 23, 2013 at 5:18 pm
Certainly no need to use a WHILE loop here. This should do it for you:
WITH SampleData (MyStr) AS
(
SELECT '12345678'
UNION ALL SELECT '12345'
UNION ALL SELECT '1234567890ABCDEFGH '
),
Tally (n) AS
(
SELECT TOP (2000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM sys.all_columns
),
StringsSplit AS
(
SELECT MyStr, a=SUBSTRING(a.MyStr, 4*n-3, 4), n
FROM SampleData a
CROSS APPLY
(
SELECT n
FROM Tally
WHERE n BETWEEN 1 AND 1+LEN(MyStr)/4
) b
)
SELECT MyStr
,NewStr=STUFF((
SELECT '.' + a
FROM StringsSplit c
WHERE a.MyStr = c.MyStr
ORDER BY n
FOR XML PATH('')
), 1, 1, '')
FROM SampleData a;
If you're not familiar with using a Tally table, Google it and you should find plenty of info.
Basically what I did was to split the strings on each 4 character boundary point with the Tally table and then combined them back together using FOR XML PATH.
FOR XML PATH is explained here: Creating a comma-separated list[/url] by Wayne Sheffield.
Merrry Christmas!
Edit: Forgot to mention. 2000 in the TOP clause of the Tally is based your data being VARCHAR(8000). You can reduce it to one fourth of the max length of your string.
My thought question: Have you ever been told that your query runs too fast?
My advice:
INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.
Need to UNPIVOT? Why not CROSS APPLY VALUES instead?[/url]
Since random numbers are too important to be left to chance, let's generate some![/url]
Learn to understand recursive CTEs by example.[/url]
[url url=http://www.sqlservercentral.com/articles/St
December 24, 2013 at 10:45 am
If you don't have any data longer than 24 bytes (or so), it might be easier just to "brute STUFF" it:
WITH SampleData (MyStr) AS
(
SELECT '12345678'
UNION ALL SELECT '12345'
UNION ALL SELECT '1234567890ABCDEFGH'
UNION ALL SELECT '1234567890ABCDEFGHIJK'
)
SELECT
MyStr,
CASE WHEN LEN(MyStr) < 05 THEN MyStr
WHEN LEN(MyStr) < 09 THEN STUFF(MyStr, 5, 0, '.')
WHEN LEN(MyStr) < 13 THEN STUFF(STUFF(MyStr, 5, 0, '.'), 10, 0, '.')
WHEN LEN(MyStr) < 17 THEN STUFF(STUFF(STUFF(MyStr, 5, 0, '.'), 10, 0, '.'), 15, 0, '.')
WHEN LEN(MyStr) < 21 THEN STUFF(STUFF(STUFF(STUFF(MyStr, 5, 0, '.'), 10, 0, '.'), 15, 0, '.'), 20, 0, '.')
ELSE STUFF(STUFF(STUFF(STUFF(STUFF(MyStr, 5, 0, '.'), 10, 0, '.'), 15, 0, '.'), 20, 0, '.'), 25, 0, '.')
END
FROM SampleData
SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".
December 24, 2013 at 12:04 pm
ScottPletcher (12/24/2013)
If you don't have any data longer than 24 bytes (or so), it might be easier just to "brute STUFF" it:
Awesome! I don't believe anything will come close to touching that for speed.
--Jeff Moden
Change is inevitable... Change for the better is not.
December 24, 2013 at 1:24 pm
Jeff Moden (12/24/2013)
ScottPletcher (12/24/2013)
If you don't have any data longer than 24 bytes (or so), it might be easier just to "brute STUFF" it:
Awesome! I don't believe anything will come close to touching that for speed.
Thanks :blush:
The really cool part was getting to legitimately use ' "brute STUFF" it' in a sentence ;-).
Edit: Corrected typo.
SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".
December 24, 2013 at 5:41 pm
ScottPletcher (12/24/2013)
Jeff Moden (12/24/2013)
ScottPletcher (12/24/2013)
If you don't have any data longer than 24 bytes (or so), it might be easier just to "brute STUFF" it:
Awesome! I don't believe anything will come close to touching that for speed.
Thanks :blush:
The really cool part was getting to legitimately use ' "brute STUFF" it' in a sentence ;-).
Edit: Corrected typo.
BWAAA_HAAA!!!! I know what you mean! I'm not one to use Hungarian Notation but I couldn't resist the temptation to use it on a "Tally" function so that I could admonish folks, "Well, if you had used the fn_Tally function I wrote for you, you wouldn't be in such a pickle" and not have it be an HR violation. 😀
Merry Christmas and Happy New Year to you and yours, Scott.
--Jeff Moden
Change is inevitable... Change for the better is not.
December 24, 2013 at 7:05 pm
Jeff Moden (12/24/2013)
Well, if you had used the fn_Tally function I wrote for you, you wouldn't be in such a pickle
That took more than a minute to sink in but I finally got it while drinking my coffee, causing two streams of dark liquid to be expelled noisily from my nostrils.
Merry Christmas to all!
My thought question: Have you ever been told that your query runs too fast?
My advice:
INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.
Need to UNPIVOT? Why not CROSS APPLY VALUES instead?[/url]
Since random numbers are too important to be left to chance, let's generate some![/url]
Learn to understand recursive CTEs by example.[/url]
[url url=http://www.sqlservercentral.com/articles/St
February 13, 2014 at 2:11 pm
I apologize for not responding to this for so long. I got dragged away to a different project and in the meanwhile this issue became a moot point. I appreciate everyone's help anyway. I've marked the "Brute Stuff" (hee hee) answer as "the answer" because I think it would've worked the best for my case. Thanks everyone!
Viewing 12 posts - 1 through 11 (of 11 total)
You must be logged in to reply to this topic. Login to reply