Reputation: 2552
We have a table which contains XML describing a group of orders which is sent by a remote function. Each row also contains things like an ID, timestamp etc of when the list of orders arrived in our system.
To illustrate:
id | date | XML
1 2012-10-20 06:51:13.683 <customer name="Bill"><order oId="1">...</order><order oId="2>...</customer>
2 2012-10-20 07:30:32.833 <customer name="Ben"><order oId="23">...</order></customer>
I want to select all the orders out, but I also want each order to be selected alongside it's id and date. Some hypothetical results:
id | date | Customer | OrderId
1 2012-10-20 06:51:13.683 Bill 1
1 2012-10-20 06:51:13.683 Bill 2
2 2012-10-20 06:51:13.683 Ben 23
Looking around, I've found lots of answers like Select XML nodes using TSQL but these only deal with selecting the first instance of a node. I want to select every order node along with the other table information it's associated with.
Thanks.
Upvotes: 0
Views: 946
Reputation: 17560
You'll have to update the names for your columns, but this is the approach I used:
SELECT xmlviewId, myDate
, myXml.value('(customer[1]/@name)', 'varchar(10)') AS CustomerName
, orders.value('@oId', 'VARCHAR(10)') AS OrderId
, orders.value('../@name', 'VARCHAR(10)') AS AlternateWayToGEtCustomerName
FROM xmlView
CROSS APPLY myXml.nodes('//order') AS c(orders);
SQL Fiddle Example
Here's a good example for xquery value
I added a second way to obtain the customerName, depending on your preference.
Upvotes: 2
Reputation: 117485
I think it's more logical to do it in two applies
select
tt.id,
tt.date,
cust.col.value('@name', 'nvarchar(128)') as Customer,
ord.col.value('@oId', 'int') as OrderId
from tt as tt
outer apply tt.[xml].nodes('/customer') as cust(col)
outer apply cust.col.nodes('order') as ord(col)
but you can also do it in one apply
select
tt.id,
tt.date,
ord.col.value('../@name', 'nvarchar(128)') as Customer,
ord.col.value('@oId', 'int') as OrderId
from tt as tt
outer apply tt.[xml].nodes('/customer/order') as ord(col)
Upvotes: 2
Reputation: 69789
You can use @
to specify an attribute, so your query would be something like this:
DECLARE @T TABLE (ID INT, [Date] DATETIME, [XML] XML);
INSERT @T VALUES
(1, '20121020 06:51:13.683', '<customer name="Bill"><order oId="1"></order><order oId="2"></order></customer>'),
(2, '20121020 07:30:32.833', '<customer name="Ben"><order oId="23"></order></customer>');
SELECT ID,
[Date],
[Customer] = [XML].value('(customer/@name)[1]', 'nvarchar(200)'),
[OrderID] = t.Orders.value('(@oId)[1]', 'int')
FROM @T
CROSS APPLY [XML].nodes('/customer/order') t (Orders)
Upvotes: 0