-1

I have a SQL Server table with 2 XML columns in a table as shown here:

Column A Column B Column C
Test1 XML Value XML Value1
Test2 XMLValue2 XML Value3

XML values look like this:

<collection>
    <object> 
        <fields> 
            <field>
                 <value>Savings account</value>
            </field>
        </fields>
    </object>
    <object>
        <fields>
             <field>
                 <value>Mortgage</value>
             </field>
        </fields>
    </object>
</collection>

I want to display result as shown here:

Column A Column B Column C
Test1 Saving Accounts, Mortage Saving Accounts, Mortage
Test2 Saving Accounts, Mortage Saving Accounts, Mortage

I am trying to use below one, but it gives me result for only one column.

select t.N.value('value[1]','varchar(max)')
from @x.nodes('/collection/object/fields/field') as t(N)

OR

@x.query('/collection/object/fields/field/value[1]')

Can anyone help me solve this problem?

2
  • 2
    You probably need to use a subquery for each column parroting the above xml nodes thing, and also, if there are multiple values you need to concatenate them somehow. A real example with all four columns will probably clarify things a bit more Commented Aug 3, 2024 at 8:17
  • While asking a question, you need to provide a minimal reproducible example: (1) DDL and sample data population, i.e. CREATE table(s) plus INSERT T-SQL statements. (2) What you need to do, i.e. logic and your code attempt implementation of it in T-SQL. (3) Desired output, based on the sample data in the #1 above. (4) Your SQL Server version (SELECT @@version;). Commented Aug 4, 2024 at 1:25

3 Answers 3

2

A simplified example (using only one XML column) will look like this:

drop table if exists #Temp;

create table #Temp (
    Name varchar(50) not null,
    XMLData xml null
);

insert into #Temp (Name, XMLData)
values ('Test1', N'<collection>
    <object> 
        <fields> 
            <field>
                 <value>Savings account</value>
            </field>
        </fields>
    </object>
    <object>
        <fields>
             <field>
                 <value>Mortgage</value>
             </field>
        </fields>
    </object>
</collection>'),
('Test3', null);

select t.Name, x1.ValueList
from #Temp t
    cross apply (
        select string_agg(v.c.value('.', 'varchar(max)'), ', ') as [ValueList]
        from t.XMLData.nodes('/collection/object/fields/field/value') v(c)
    ) x1;

You'll need a separate subquery like x1 for each XML column in the source.

Note that string_agg() function is only available in SQL Server 2017 or later versions. Prior to that, you'd have to implement concatenation using FOR XML PATH, like this.

Sign up to request clarification or add additional context in comments.

Comments

1

Please try the following solution based on SQL Server's pure XQuery.

SQL

-- DDL and sample data population, start
DECLARE @tbl table (Name varchar(50) not null, XMLData xml null);
INSERT INTO @tbl (Name, XMLData) values 
('Test1', N'<collection>
    <object> 
        <fields> 
            <field>
                 <value>Savings account</value>
            </field>
        </fields>
    </object>
    <object>
        <fields>
             <field>
                 <value>Mortgage</value>
             </field>
        </fields>
    </object>
</collection>'),
('Test3', null);
-- DDL and sample data population, end

SELECT Name
    , XMLData.query('
        let $last := (/collection/object/fields/field/value)[last()] 
        for $i in /collection/object/fields/field/value
        return if ($i is $last[1]) then data($i)
            else concat(data($i), ",")
    ').value('text()[1]', 'NVARCHAR(MAX)') AS Result
FROM @tbl;

Output

Name Result
Test1 Savings account, Mortgage
Test3 NULL

Comments

0

If you don't mind a trailing comma then you can actually concatenate within XQuery.

select
  t.Name,
  t.XMLData.query('for $i in /collection/object/fields/field/value/text() return concat($i, ", ")').value('text()[1]', 'nvarchar(max)') 
from #Temp t;

.query will just lump all the text nodes together. The .value is necessary to prevent XML escaping/entitization.

1 Comment

You're right, should have been concat($i not concat(. dbfiddle.uk/xsclDnfM

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.