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.
Author |
Topic |
bopritchard
Starting Member
3 Posts |
Posted - 2010-09-23 : 11:29:02
|
code description1500 Hat Tie Shoes Boots1500 Tie Blue Red Cat1500 Shoes Red Fish Cup1650 Hello Seed Tree1650 Seed Pencil Paper1650 Knife Phone TreeI need a single row for each code with a description of each unique word in the description column. there are no set number of rows per code. SQLServer 2000Really appreciate help on this one.So my results should look like1500 Hat Tie Shoes Boots Blue Red Cat Fish Cup1650 Hello Seed Tree Pencil Paper Knife Phone |
|
Transact Charlie
Master Smack Fu Yak Hacker
3451 Posts |
Posted - 2010-09-23 : 11:59:56
|
This would be sooooooo much easier on 2005 or better?Can you upgrade.I'm puzzling out a 2000 solution but it'll be messy.Charlie===============================================================Msg 3903, Level 16, State 1, Line 1736The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION |
|
|
Transact Charlie
Master Smack Fu Yak Hacker
3451 Posts |
Posted - 2010-09-23 : 12:08:54
|
Here's a way. It's horrible. Would be both much shorter and much nicer on 2005. Wouldn't have a cursor......It would be betterNote -- I've changed the code column to cDef so that it doesn't get in the way of the code tags......Written on a database in compatibility 80 (2000) However NOT ON A 2000 Server. Not sure if it will all work on 2000 dbDROP FUNCTION CG_PARSE_ARRAYGOCREATE FUNCTION CG_PARSE_ARRAY ( @array VARCHAR(8000) , @separator CHAR(1) = ' ' )RETURNS @return TABLE ( [ID] INT IDENTITY(1,1) PRIMARY KEY , [value] VARCHAR(8000) )AS BEGIN -- @Array is the array we wish to parse -- @Separator is the separator charactor such as a comma DECLARE @separator_position INT -- This is used to locate each separator character DECLARE @array_value VARCHAR(8000) -- this holds each array value as it is returned -- For my loop to work I need an extra separator at the end. I always look to the -- left of the separator character for each array value SET @array = @array + @separator -- Loop through the string searching for separtor characters WHILE ( PATINDEX('%' + @separator + '%' , @array) <> 0 ) BEGIN -- patindex matches the a pattern against a string SELECT @separator_position = PATINDEX('%' + @separator + '%' , @array) SELECT @array_value = left(@array, @separator_position - 1) -- This is where you process the values passed. -- Replace this select statement with your processing -- @array_value holds the value of this element of the array INSERT @return ([value]) SELECT @array_value -- This replaces what we just processed with and empty string SELECT @array = STUFF(@array, 1, @separator_position, '') END RETURN ENDGODECLARE @dataSet TABLE ( [cDef] INT , [description] VARCHAR(8000) )INSERT @dataSet ([cDef], [description]) SELECT 1500, 'Hat Tie Shoes Boots'UNION SELECT 1500, 'Tie Blue Red Cat'UNION SELECT 1500, 'Shoes Red Fish Cup'UNION SELECT 1650, 'Hello Seed Tree'UNION SELECT 1650, 'Seed Pencil Paper'UNION SELECT 1650, 'Knife Phone Tree'SELECT * FROM @dataSet-- Make the MapDECLARE @map TABLE ([cDef] INT, [description] VARCHAR(8000))-- Cursor (pah -- 2000 LONG FOR CROSS APPLY!)DECLARE popCursor CURSOR LOCAL READ_ONLY FORSELECT [cDef], [description] FROM @dataSetDECLARE @code INTDECLARE @description VARCHAR(8000)OPEN popCursor FETCH NEXT FROM popCursor INTO @code, @description WHILE ( @@FETCH_STATUS = 0 ) BEGIN INSERT @map ([cDef], [description]) SELECT @code , p.[value] FROM dbo.CG_PARSE_ARRAY (@description, ' ') AS p WHERE NOT EXISTS ( SELECT 1 FROM @map AS m WHERE m.[cDef] = @code AND m.[description] = p.[value] ) FETCH NEXT FROM popCursor INTO @code, @description ENDCLOSE popCursorDEALLOCATE popCursorSELECT * FROM @map-- ConcatenateSELECT [cDef] , ( SELECT [description] + ' ' FROM @map AS m2 WHERE m2.[cDef] = m.[cDef] ORDER BY m2.[description] FOR XML PATH('') ) AS [descriptions]FROM ( SELECT DISTINCT [cDef] FROM @map ) AS m Charlie===============================================================Msg 3903, Level 16, State 1, Line 1736The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION |
|
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2010-09-23 : 12:13:34
|
Do you need to maintain the order, i.e. 1500 Hat Tie Shoes Boots Blue Red Cat Fish Cup, or could they be in alphabetical order? |
|
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2010-09-23 : 12:15:08
|
FYI TransactCharlie, FOR XML PATH is a 2005 feature. |
|
|
Transact Charlie
Master Smack Fu Yak Hacker
3451 Posts |
Posted - 2010-09-23 : 12:15:43
|
my solution reorders then alphabetically.without the order by I think it would be random.Charlie===============================================================Msg 3903, Level 16, State 1, Line 1736The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION |
|
|
Transact Charlie
Master Smack Fu Yak Hacker
3451 Posts |
Posted - 2010-09-23 : 12:16:28
|
quote: Originally posted by robvolk FYI TransactCharlie, FOR XML PATH is a 2005 feature.
Why does it work on my database that is compatibility level 80 then?Charlie===============================================================Msg 3903, Level 16, State 1, Line 1736The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION |
|
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2010-09-23 : 12:18:17
|
A lot of 2005 features work in compatibility mode, but they won't work on an actual 2000 server. |
|
|
Transact Charlie
Master Smack Fu Yak Hacker
3451 Posts |
Posted - 2010-09-23 : 12:19:14
|
ah. right. That's annoying.Charlie===============================================================Msg 3903, Level 16, State 1, Line 1736The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION |
|
|
bopritchard
Starting Member
3 Posts |
Posted - 2010-09-23 : 12:19:28
|
quote: Originally posted by robvolk Do you need to maintain the order, i.e. 1500 Hat Tie Shoes Boots Blue Red Cat Fish Cup, or could they be in alphabetical order?
Order doesn't matter |
|
|
robvolk
Most Valuable Yak
15732 Posts |
Posted - 2010-09-23 : 13:41:22
|
Well, it doesn't use a cursor:-- creates a "Tally" table (#n) of numbers-- skip this part if you already have a tally table, and change the name belowcreate table #n(n smallint not null primary key)insert #n values(1)while (select max(n) from #n)<8000insert #n select n+(select max(n) from #n) from #n where n+(select max(n) from #n)<=8000-- sample datacreate table #a(code int not null, description varchar(1024) not null)insert #a (code, description)select 1500, 'Hat Tie Shoes Boots' union all select 1500, 'Tie Blue Red Cat' union all select 1500, 'Shoes Red Fish Cup' union all select 1650, 'Hello Seed Tree' union all select 1650, 'Seed Pencil Paper' union all select 1650, 'Knife Phone Tree'-- temp table to hold split wordscreate table #results(code int not null, word varchar(128) not null)-- query to split wordsinsert #results(code, word)select distinct code, ltrim(rtrim(substring(d, n, charindex(' ', d, n+1)-n)))from (select code, ' '+description+' ' d from #a) z -- subquery to simplify the substring expressioncross join #nwhere n<len(d) and substring(d,n-1,1)=' ' -- temp table to hold concatenated resultscreate table #merge (code int not null primary key, description varchar(8000))insert #merge select code, min(word) from #results group by code-- loop through words, concatenate, then remove from #resultswhile @@rowcount>0 begin delete r from #results r inner join #merge m on m.code=r.code where m.description like '%'+r.word update m set description=description+' '+r.word from #merge m inner join (select code, min(word) word from #results group by code) r on m.code=r.codeendselect * from #merge The black text is the setup, the blue text is the meat of it. Change references to #a and #n as needed. This is based on an old article of mine:http://www.sqlteam.com/article/parsing-csv-values-into-multiple-rowsI still think it's kinda ugly but it should do the trick. I hate to say that a cursor approach might be faster; at least I won't write it. |
|
|
|
|
|
|
|