Nic
Nic

Reputation: 127

SQL variable concatenation with xml

have the following table coming from this query:

SELECT 
     [Document], 
     [Description], 
     [Value], 
FROM [DocDetails]

Document    Description      Value      Line No_
  120         First Row       100              1
  120         Second Row      0                2
  120         Third row       0                3
  120         Fourth row      0                4 
  120         fifth row       0                5
  120         sixth row       203              6
  120         seventh row     256              7
  120         eighth row      259              8
  120         ninth row       0                9
  120         tenth row       0                10
  120         eleventh row    0                11

I need to concatenate the description according to the value. I would need such result:

Document    Description                                              Value
  120         First Row;second row;Third row;Fourth row;fifth row     100
  120         sixth row                                               203
  120         seventh row                                             256
  120         eighth row;ninth row;tenth row;eleventh row             259

I tried the following:

SELECT 
  [Document], 
  All_Descriptions = STUFF(
         (SELECT ';' + Description AS [text()]
          FROM [DocDetails] D1
          WHERE D1.[Document] = D2.[Document] 
          FOR XML PATH('')),1,1,'')
          FROM [DocDetails] D2
              GROUP BY D2.[Document]

As I don't have a variable that specifies the order I am not able to concatenate properly ( the code above concatenates everything but that's not what I want). Also if I group by value I am not getting the desired result. How can I tell SQL to basically "concatenate the row with an amount with all the following having value 0"

Thanks for your help!

Upvotes: 3

Views: 72

Answers (2)

Serkan Arslan
Serkan Arslan

Reputation: 13393

This is another solution that works with SQL 2008 too.

DECLARE @DocDetails TABLE( [Document] int, [Description] varchar(20), [Value] int, [Line_No] int )
INSERT INTO @DocDetails VALUES
    (120,'First Row',100,1),
    (120,'Second Row',0,2),
    (120,'Third row',0,3),
    (120,'Fourth row',0,4),
    (120,'fifth row',0,5),
    (120,'sixth row',203,6),
    (120,'seventh row',256,7),
    (120,'eighth row',259,8),
    (120,'ninth row',0,9),
    (120,'tenth row',0,10),
    (120,'eleventh row',0,11),
    (121,'eleventh row',0,11)

;WITH 
LinesWithValue AS (
    SELECT *, ROW_NUMBER() OVER(PARTITION BY [Document] ORDER BY Line_No ) RN
    FROM @DocDetails 
    WHERE Value > 0 
)
,LinesWithNext AS (
    SELECT L.*, L1.Line_No Next_Line_No 
    FROM LinesWithValue L 
    LEFT JOIN LinesWithValue L1 ON L.RN + 1 = L1.RN AND L.[Document] = L1.[Document]
 )
,NewTable AS (SELECT 
    B.Document, 
    B.Description, 
    CASE B.Value WHEN 0 THEN A.Value ELSE B.Value END Value, 
    B.Line_No 
    FROM LinesWithNext A 
    FULL JOIN @DocDetails B ON A.[Document] = B.[Document] AND ( ( B.Line_No >= A.Line_No ) AND ( A.Next_Line_No IS NULL OR  B.Line_No < A.Next_Line_No ) )
 )
 SELECT 
   [Document], 
   [Value],
   All_Descriptions = STUFF(
         (SELECT ';' + Description AS [text()]
         FROM NewTable D1
         WHERE D1.[Document] = D2.[Document] AND D1.[Value] = D2.[Value]
         FOR XML PATH('')) , 1, 1, '')
 FROM NewTable D2
 GROUP BY D2.[Document], [Value]

Upvotes: 2

S3S
S3S

Reputation: 25112

Here's a way....

declare @table table(Document int,[Description] varchar(64), [Value] int, Line_No int)
insert into @table
values
(120,'First Row',100,1),
(120,'Second Row',0,2),
(120,'Third row',0,3),
(120,'Fourth row',0,4),
(120,'fifth row',0,5),
(120,'sixth row',203,6),
(120,'seventh row',256,7),
(120,'eighth row',259,8),
(120,'ninth row',0,9),
(120,'tenth row',0,10),
(120,'eleventh row',0,11)

--Find the end / anchor line which to stop the concatenation later
;with cte as(
select
    t.Document
    ,t.[Value]
    ,t.Description
    ,t.Line_No
    ,Parent_Line = isnull(min(t2.Line_No) - 1, (select max(Line_No) from @table))
from
    @table t
    full join
    @table t2 on t2.Document = t.Document 
    and t2.Line_No > t.Line_No
    and t2.Value <> 0
where
    t.Document is not null
group by
    t.Document
    ,t.[Value]
    ,t.Line_No
    ,t.Description),

--Do the concatenation of the Description
cte2 as (
select
    Document
    ,value
    ,All_Descriptions = STUFF((
        SELECT ',' + t2.Description
        FROM cte t2
        WHERE t.Parent_Line = t2.Parent_Line
        FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
    ,Parent_Line
from
    cte t)

--Get max [Value] for uniqueness
select
    Document
    ,All_Descriptions
    ,[Value] = max([Value])
from 
    cte2
group by
    Document
    ,All_Descriptions
order by
    max([Value])

Upvotes: 1

Related Questions