June 12, 2007 at 2:52 am
I need to retrieve the latest description on a specific case. I am joining to the following table using the max(index) derived elsewhere in the code by means of a subquery.
The way that the database has designed is that the description for one particular index can span one to n number of records. I need to be able to concatenate all the seperate records into 1 varchar(250) field to include within a report.
Below I have included sample data for one particular record. Thanks for your help
Index LineNo Desc
46913229 1 Test test test124
46913229 2 Test test test241
46913229 3 Test test test012
46913229 4 Test test test741
46913229 5 Test test test665
46913229 6 Test test test423
46913229 7 Test test test478
46913229 8 Test test test4487
46913229 9 Test test test54
June 12, 2007 at 3:53 am
I'm sure someone with a bigger brain than me could come up with a better solution, but the following does the trick. you could turn the loop into a function that returns the string you want without too much trouble.
Hope it helps.
S
set nocount on
declare @table table
([Index] int, [LineNo] int,[Desc] varchar(20))
declare @LineNo int
declare @MyString varchar(250)
insert into @table
select 46913229, 1,'Test test test124'
union
select 46913229, 2,'Test test test241'
union
select 46913229, 3,'Test test test012'
union
select 46913229, 4,'Test test test741'
union
select 46913229, 5,'Test test test665'
union
select 46913229, 6,'Test test test423'
union
select 46913229, 7,'Test test test478'
union
select 46913229, 8,'Test test test4487'
union
select 46913229, 9,'Test test test54'
select @MyString = ''
select @LineNo = min([LineNo])
from @table
while @LineNo is not null
begin
select @MyString = @MyString + ' ' + [Desc]
from @table
where [LineNo] = @LineNo
select @LineNo = min([LineNo])
from @table
where [LineNo] > @LineNo
end
select @MyString
June 12, 2007 at 4:25 am
Does this help?
USE SSC
GO
-- How do I concatenate rows into a single column?
-- Short answer is you should never do this when an outside application is presenting the data and that application is able to format the data for you.
-- However if the report is to be run on the server and e-mailed or something like that (no presentation layer), here's how you do it :
-- You first create a function. For the sake of simplicity I will not pass any parameters to the function but the rules that say you should never return more data than needed still applies.
-- Let's say I want to return all system table names into a single column, I would do it like so :
GO
IF EXISTS (SELECT * FROM dbo.SysObjects WHERE Name = 'Concat1' AND XType = 'FN' AND USER_NAME(uid) = 'dbo')
DROP FUNCTION dbo.Concat1
GO
CREATE FUNCTION dbo.Concat1()
RETURNS NVARCHAR(4000)
AS
BEGIN
DECLARE @Return AS NVARCHAR(4000)
SELECT @Return = COALESCE (@Return + ', ' + Name, Name) FROM dbo.SysObjects WHERE XType = 'S' ORDER BY Name
RETURN @Return
END
GO
SELECT dbo.Concat1() AS SysTables
/*
SysTables
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
syscolumns, syscomments, sysdepends, sysfilegroups, sysfiles, sysfiles1, sysforeignkeys, sysfulltextcatalogs, sysfulltextnotify, sysindexes, sysindexkeys, sysmembers, sysobjects, syspermissions, sysproperties, sysprotects, sysreferences, systypes, sysusers
(1 row(s) affected)
*/
-- This works great, however we now want to have a list of all the columns for each system table in the same order they are presented in enterprise manager, so the result set we want is now "TableName, ListOfColumns"
-- It would go something like this
GO
IF EXISTS (SELECT * FROM dbo.SysObjects WHERE Name = 'Concat2' AND XType = 'FN' AND USER_NAME(uid) = 'dbo')
DROP FUNCTION dbo.Concat2
GO
CREATE FUNCTION dbo.Concat2(@id AS INT)
RETURNS NVARCHAR(4000)
AS
BEGIN
DECLARE @Return AS NVARCHAR(4000)
SELECT @Return = COALESCE (@Return + ', ' + Name, Name) FROM dbo.SysColumns WHERE id = @id ORDER BY Colid
RETURN @Return
END
GO
--Now we need to call the function from within a query instead of simply calling the function all by itself
SELECT Name AS TableName, dbo.Concat2(id) AS ColumnsList FROM dbo.SysObjects WHERE XType = 'S' ORDER BY Name
/*
TableName ColumnsList
-------------------------------------------------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
syscolumns name, id, xtype, typestat, xusertype, length, xprec, xscale, colid, xoffset, bitpos, reserved, colstat, cdefault, domain, number, colorder, autoval, offset, collationid, language, status, type, usertype, printfmt, prec, scale, iscomputed, isoutparam, isnullable, collation, tdscollation
syscomments id, number, colid, status, ctext, texttype, language, encrypted, compressed, text
...
sysusers uid, status, name, sid, roles, createdate, updatedate, altuid, password, gid, environ, hasdbaccess, islogin, isntname, isntgroup, isntuser, issqluser, isaliased, issqlrole, isapprole
(19 row(s) affected)
*/
June 12, 2007 at 6:38 am
Adam...
What do you want to happen if the amount of data exceeds the VARCHAR(250) column you've outlined?
--Jeff Moden
Change is inevitable... Change for the better is not.
June 12, 2007 at 7:17 am
same goes for varcharcolumns of 8000
Indeed these kind of constructions will have a cost !
CREATE FUNCTION [dbo].[fn_ALZDBA_GetFullDescription](@Index int)
RETURNS @tblFullDescription TABLE
(RefIndex int not null, Description Text not NULL)
AS
BEGIN
Insert into @tblFullDescription (RefIndex, Description) values (@Index, '')
declare @LineNo int
Set @LineNo = 1
While 1 = 1
begin
Update TVF
set Description = Description + T.Desc
from @tblFullDescription TVF
inner join yourtable T
on TVF.RefIndex = T.Index
and T.LineNo = @LineNo
if @@rowcount = 0 break
Set @LineNo = @LineNo + 1
end
RETURN
END
TEST it TEST it
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
June 12, 2007 at 8:45 am
Hi All,
Thanks for your help.
ALZDBA I am trying to test your function now but I cannot understand what values you are passing to the function?
Can you give me an example of how it works based upon by test data as above. If you could use the column names it would help me a lot.
Thanks again
June 12, 2007 at 8:49 am
I think I have worked out what your doing now. This is what I have so far using the real column names...
I get this error and cannot work out what it relates to, it puts me on this line Update TVF
Server: Msg 403, Level 16, State 1, Procedure fn_GetFullDescription, Line 12
Invalid operator for data type. Operator equals add, type equals text.
CREATE FUNCTION [fn_GetFullDescription](@Index int)
RETURNS @tblFullDescription TABLE
(RefIndex int not null, tddesc Text not NULL)
AS
BEGIN
Insert into @tblFullDescription (RefIndex, tddesc) values (@Index, '')
declare @LineNo int
Set @LineNo = 1
While 1 = 1
begin
Update TVF
set tvf.tddesc = tvf.tddesc + T.tddesc
from @tblFullDescription TVF
inner join TimeDesc T
on TVF.RefIndex = T.tdtcIndex
and T.tdline = @LineNo
if @@rowcount = 0 break
Set @LineNo = @LineNo + 1
end
RETURN
END
June 12, 2007 at 8:51 am
I changed the text datatype to a varchar(250) and it create the function.
If the data exceeds 250 I want to truncate the data as it will be used in Crystal 8 which doesn't support anything over 250 characters!
June 12, 2007 at 8:56 am
Ok I have tested the function but it does return an error when the data exceeds 250 characters. What is the best way to get round this?
Use a convert function within the funtion I have created?
June 12, 2007 at 9:03 am
Declare tddesc as varchar(250) and you should be golden (untested).
June 12, 2007 at 9:51 am
I've been to quick with my response using a text column
Aparently text/image operators cannot be used in functions
I tested this :
CREATE FUNCTION [fn_GetFullDescription](@Index int)
RETURNS @tblFullDescription TABLE
(RefIndex int not null, tddesc Text not NULL)
AS
BEGIN
Insert into @tblFullDescription (RefIndex, tddesc) values (@Index, '')
DECLARE @ptrval varbinary(16)
Declare @BeginPos int
Declare @tddesc varchar(8000)
declare @LineNo int
Set @LineNo = 1
While 1 = 1
begin
SELECT @ptrval = TEXTPTR(TVF.tddesc)
, @tddesc = T.tddesc
, @BeginPos= datalength(TVF.tddesc)
from @tblFullDescription TVF
inner join T_desc T
on TVF.RefIndex = T.[Index]
and T.[LineNo] = @LineNo
and T.[Index] = @index
if @@rowcount = 0 break
UPDATETEXT @tblFullDescription.tddesc @ptrval (@BeginPos + 1) datalength(@tddesc) @tddesc
Set @LineNo = @LineNo + 1
end
RETURN
END
go
select *
, dbo.fn_GetFullDescription(T1.[index])
from T1
And got the error :
Server: Msg 443, Level 16, State 1, Procedure fn_GetFullDescription, Line 39
Invalid use of 'textptr' within a function.
Back to the varchar(8000) solution.
So don't use a TVF but just return the resultstring.
I'm sorry I've put you on a dead end
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
June 12, 2007 at 5:16 pm
THAT's one of the things I like about you, ALZDBA!! Need more folks that can come back and say "Dang, made a mistake". Rare breed indeed
--Jeff Moden
Change is inevitable... Change for the better is not.
June 12, 2007 at 5:18 pm
Adam,
Are you all set have Remi's suggestion or are you still having problems?
--Jeff Moden
Change is inevitable... Change for the better is not.
June 12, 2007 at 6:15 pm
I try to keep my demos as simple as possible, but when you never understood the concept, it still can be pretty hard to understand when you first look at it.
Make sure you get your questions answered, so that maybe I can even further simplify this thing.
June 12, 2007 at 8:56 pm
But it can be used in stored procedure...
Yes, you cannot use SP call in select statement, but if you're bad enough to pass set of more than 8k strings to client then looping would not make it any worse.
_____________
Code for TallyGenerator
Viewing 15 posts - 1 through 15 (of 16 total)
You must be logged in to reply to this topic. Login to reply