views:

40

answers:

2

I've inherited a stored procedure that uses FOR XML PATH in a subselect to concatenate multiple result rows from the subselect into a single result column on the "main" query. Consider the following, where table "z" is part of the main query's FROM clause:

SELECT SUBSTRING((SELECT ('; ' + RTRIM(c.SomeField))
FROM a (NOLOCK)
INNER JOIN b (NOLOCK) ON a.aid = b.aid
INNER JOIN c (NOLOCK) ON b.cid = c.cid
WHERE a.zid = z.zid
FOR XML PATH('')), 3, 1000)

This returns the following, if there were three result rows from the subselect:

value1; value2; value3

Most of the time, this works great. However, several of the values for c.SomeField, which is a varchar, have special XML characters in them, most frequently the ampersand. So, when one of the values has an ampersand, I get this:

value1 & more value1; value2; value3

Is there another way I can concatenate these row results together? If not, is there a simple way to decode the string in .NET?

+1  A: 

You can run these statements as one batch to get what you want:

declare @s as varchar(max); 
select @s = isnull(@s + '; ', '') + SomeField
from (
    SELECT RTRIM(c.SomeField) as SomeField
    FROM a (NOLOCK) 
    INNER JOIN b (NOLOCK) ON a.aid = b.aid 
    INNER JOIN c (NOLOCK) ON b.cid = c.cid 
    WHERE a.zid = z.zid 
) a; 
select @s as SomeFieldList; 

Update: here is a proof of concept without using your schema:

declare @s as varchar(max);  
select @s = isnull(@s + '; ', '') + SomeField
from ( 
    SELECT 'aaa' as SomeField
    UNION ALL
    SELECT 'bbb' 
    UNION ALL
    SELECT 'ccc' 
) a;  
select @s as SomeFieldList; 
RedFilter
I can't embed this as a subselect though, which is what I need to do.
AJ
Please post the entire query.
RedFilter
After 40 min of trying to make this procedure "safe to post," I give up. It's rather massive, and I'm not sure I could put it up here without screwing something up.
AJ
Even running this script alone with a literal value for z.zid doesn't work.
AJ
@AJ - not sure what you mean by *doesn't work*.
RedFilter
@AJ: see my update for a proof of concept example.
RedFilter
+1  A: 

From MVP Rob Farley:

SELECT SUBSTRING((
  SELECT ('; ' + RTRIM(c.SomeField))
  FROM a (NOLOCK)
  INNER JOIN b (NOLOCK) ON a.aid = b.aid
  INNER JOIN c (NOLOCK) ON b.cid = c.cid
  WHERE a.zid = z.zid
  FOR XML PATH(''), ROOT('xml'), TYPE
).value('/xml[1]','varchar(max)'), 3, 1000)

He points out:

However, if I actually make my FOR XML call return actual well-formed XML, then I can extract the contents out, and it returns the data to me in its original (correct) form.

8kb
Not sure what .value is, but this works perfectly! Thank you very much.
AJ
@AJ: The title of this question says *"without using FOR XML PATH"*.
RedFilter