I have a table which contains a XML column and I need to get a value from the XML.
<ArrayOfItem>
<Item>
<Key>Member_Claim_Id</Key>
<Value>1802538</Value>
</Item>
<Item>
<Key>Reverify</Key>
<Value>0</Value>
</Item>
<Item>
<Key>RequestNumber</Key>
<Value>First Request</Value>
</Item>
</ArrayOfItem>
Sometimes Reverify key will be present in the XML document, and other times it won't. The document can contain other key / value pairs as well.
But RequestNumber key / value pair will always be present, but it might be the second or third key / value item in the document. So I could have:
<ArrayOfItem>
<Item>
<Key>Member_Claim_Id</Key>
<Value>1802538</Value>
</Item>
<Item>
<Key>RequestNumber</Key>
<Value>First Request</Value>
</Item>
</ArrayOfItem>
Currently I am using this:
SELECT TOP 10 *
FROM dbo.myTable
WHERE Parameters.value('(/ArrayOfItem/Item/Value)[2]', 'varchar(max)') LIKE '%revision%'
ORDER BY Id DESC
But I was assuming that RequestNumber was always the 2nd Key/Value Item in the document, but I just learned that that is not always the case.
Let's say the table looks like:
CREATE TABLE dbo.myTable
(
Parameters XML NOT NULL,
Field1 VARCHAR(50) NULL
)
INSERT INTO dbo.myTable (Parameters, Field1)
VALUES
( '<ArrayOfItem>
<Item>
<Key>Member_Claim_Id</Key>
<Value>1802538</Value>
</Item>
<Item>
<Key>Reverify</Key>
<Value>0</Value>
</Item>
<Item>
<Key>RequestNumber</Key>
<Value>First Request</Value>
</Item>
</ArrayOfItem>', -- XMLParameters - xml
'myText' -- Field1 - varchar(50)
)
and I want the value of /ArrayOfItem/Item/Value where the key is RequestNumber.
Thank you for your help.
Please try the following solution.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (ID INT IDENTITY PRIMARY KEY, Parameters XML NOT NULL);
INSERT INTO #tbl (Parameters) VALUES
(N'<ArrayOfItem>
<Item>
<Key>Member_Claim_Id</Key>
<Value>1802538</Value>
</Item>
<Item>
<Key>Reverify</Key>
<Value>0</Value>
</Item>
<Item>
<Key>RequestNumber</Key>
<Value>First Request</Value>
</Item>
</ArrayOfItem>');
-- DDL and sample data population, end
DECLARE #param VARCHAR(30) = 'RequestNumber';
SELECT ID
, c.value('(Key/text())[1]', 'VARCHAR(30)') AS [Key]
, c.value('(Value/text())[1]', 'VARCHAR(30)') AS [Value]
FROM #tbl
CROSS APPLY Parameters.nodes('/ArrayOfItem/Item[Key[text()=sql:variable("#param")]]') AS t(c);
Output
+----+---------------+---------------+
| ID | Key | Value |
+----+---------------+---------------+
| 1 | RequestNumber | First Request |
+----+---------------+---------------+
Related
I have a SQL table receiving orders
<XMLGateway>
<Header>
....
</Header>
<Body>
<Orders>
<Order>
<ItemCode>315689</ItemCode>
<ProductName>Item1</ProductName>
</Order>
<Order>
<ItemCode>123456</ItemCode>
<ProductName>Product 1</ProductName>
</Order>
</Orders>
</Body>
I would then like to iterate through each order and insert them separately into my Orders table
insert into orders (ItemCode,ProductName) as separate records
Is there a simpler solution than a cursor?
You can try with this XQuery statement - no cursors needed for sure!
-- you have your XML in a SQL variable here
DECLARE #input XML = '<XMLGateway>
<Body>
<Orders>
<Order>
<ItemCode>315689</ItemCode>
<ProductName>Item1</ProductName>
</Order>
<Order>
<ItemCode>123456</ItemCode>
<ProductName>Product 1</ProductName>
</Order>
</Orders>
</Body>
</XMLGateway>'
-- Commented out the "INSERT" part, so you can try what the "SELECT" returns
-- INSERT INTO dbo.Orders (ItemCode, ProductName)
SELECT
-- pick out the "ItemCode" and "ProductName" subelements from the <Order> node
ItemCode = XC.value('(ItemCode/text())[1]', 'int'),
ProductName = XC.value('(ProductName/text())[1]', 'varchar(100)')
FROM
-- get the "<Order>" XML nodes, as a list of XML fragments
#input.nodes('/XMLGateway/Body/Orders/Order') AS XT(XC)
I have data stored using XML tags in a column of a table. I am trying to pull data in a query from that column. This is a pared down skeletal version of the format of the XML and the query for a single node. The column type is XML.
<data>
<Company>
<GROUP_ID ControlType="xxxxxxxxx" ParentName="ppppppppp" Value="100" />
</Company>
</data>
This just will not pull the value "100" out no matter how I have tried. All I get is a blank, but not a NULL.
Is it because the data is not in a proper format or is my query just wrong? The p_table has the XML column (U_Xml).
select
pt.id,
x.y.value('(GROUP_ID)[1]', 'varchar(max)') AS [Group ID]
From p_table pt
CROSS APPLY pt.U_Xml.nodes('/data/Company') as x(y)
Thanks for any direction I can receive.
GROUP_ID element has no value, i.e. child text node.
It has just attributes.
Please try the following.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (id INT IDENTITY PRIMARY KEY, xmldata XML);
INSERT INTO #tbl (xmldata) VALUES
(N'<data>
<Company>
<GROUP_ID ControlType="xxxxxxxxx" ParentName="ppppppppp" Value="100"/>
</Company>
</data>');
-- DDL and sample data population, end
SELECT id
, c.value('#ControlType', 'VARCHAR(30)') AS ControlType
, c.value('#ParentName', 'VARCHAR(30)') AS ParentName
, c.value('#Value', 'INT') AS [Value]
FROM #tbl CROSS APPLY xmldata.nodes('/data/Company/GROUP_ID') AS t(c);
Output
+----+-------------+------------+-------+
| id | ControlType | ParentName | Value |
+----+-------------+------------+-------+
| 1 | xxxxxxxxx | ppppppppp | 100 |
+----+-------------+------------+-------+
This problem keeps messing around with my Friday afternoon:
I have this XML:
declare #xml as XML
set #xml =
'<fields>
<field>
<id>1</id>
<items>
<item>
<name>name1_1</name>
<value>value1_1</value>
</item>
<item>
<name>name1_2</name>
<value>value1_2</value>
</item>
</items>
</field>
<field>
<id>2</id>
<items>
<item>
<name>name2_1</name>
<value>value2_1</value>
</item>
<item>
<name>name2_2</name>
<value>value2_2</value>
</item>
</items>
</field>
</fields>'
Using T-SQL and XPath, I need a query to get this result:
id name value
1 name1_1 value1_1
1 name1_2 value1_2
2 name2_1 value2_1
2 name2_2 value2_2
I'm getting name and value with:
SELECT c.value('name[1]', 'nvarchar(255)') name,
c.value('value[1]', 'nvarchar(255)') value
FROM #xml.nodes('fields/field/items/item') t(c)
...but how to insert the parent column "id"?
Your own code uses .nodes() to get a derived table from repeating elements. In your case there are two levels of repeating elements:
many fields and within each field
many items
You have to use .nodes() twice:
SELECT fld.value(N'(id/text())[1]',N'int') AS FieldID
,itm.value(N'(name/text())[1]',N'nvarchar(max)') AS ItemName
,itm.value(N'(value/text())[1]',N'nvarchar(max)') AS ItemValue
FROM #xml.nodes(N'/fields/field') AS A(fld)
OUTER APPLY A.fld.nodes(N'items/item') AS B(itm);
The first .nodes() comes back with XML fragments, one for each field, the second node is called for each of these field-fragments to pick their items.
Use OUTER APPLY if there might be fields without <item> nodes and CROSS APPLY when you do not want to see fields without <item> nodes (similar to LEFT JOIN vs INNER JOIN)
Assumption: there is only one id element per field.
SELECT c.value('../../id[1]', 'int') id,
c.value('name[1]', 'nvarchar(255)') name,
c.value('value[1]', 'nvarchar(255)') value
FROM #xml.nodes('fields/field/items/item') t(c)
The .. operator means "select parent of node" in XPATH. So the query will select the parent of item, then the parent of items, then the first child node id
I am trying to add in a few elements in between the ROOT and PATH in a MSSQL 2008 Query. For Example I generate this something like this:
<Employees>
<Employee ID="1">
<LastName>David</LastName>
<FirstName>Larry</FirstName>
<Title>Writer</Title>
</Employee>
<Employee ID="2">
<LastName>Colbert</LastName>
<FirstName>Stephen</FirstName>
<Title>President of South Carolina</Title>
</Employee>
With
SELECT
[EmployeeID] AS '#ID',
[LastName], [FirstName],
[Title]
FROM
[dbo].[Employees]
FOR XML PATH('Employee'), ROOT('Employees')
I'd like to add a few elements like this:
<Employees>
<Company>ACME DYNAMITE</Company>
<CreateDate>JAN 01 2013</CreateDate>
<Employee ID="1">
<LastName>David</LastName>
<FirstName>Larry</FirstName>
<Title>Writer</Title>
</Employee>
<Employee ID="2">
<LastName>Colbert</LastName>
<FirstName>Stephen</FirstName>
<Title>President of South Carolina</Title>
</Employee>
I am using BCP to generate an output file so it would be possible to append a header and footer to the output file. If its possible in the query I'd like to do it that way. I have tried a variety of syntax but just can't seem to get it.
Any help is much appreciated.
SELECT
'ACME DYNAMITE' as Company,
'JAN 01 2013' as CreateDate,
(
SELECT
[EmployeeID] AS '#ID',
[LastName],
[FirstName],
[Title]
FROM
[dbo].[Employees]
FOR XML PATH('Employee'), TYPE
)
FOR XML PATH(''), ROOT('Employees')
I have some XML data stored in a varchar(max) column on SQL Server 2005. The data is in the form (FQTN = fully qualified type name):
<?xml version="1.0" encoding="utf-16"?>
<History xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<EntityViews>
<EntityProxy Type="FQTN" Key="386876" />
<EntityProxy Type="FQTN" Key="387981" />
<!-- etc. -->
</EntityViews>
</History>
How can I select Type, Key so that I get a tabular result from the XML data in this column for a single row? The table has an identity primary key named HistoryId.
;with cteCastToXML as (
select CAST(YourColumn as xml) as x
from YourTable
)
select h.ep.value('#Type','varchar(10)') as [Type],
h.ep.value('#Key', 'varchar(10)') as [Key]
from cteCastToXML
cross apply x.nodes('/History/EntityViews/EntityProxy') as h(ep)
My recommendation would be two fold.
If this is what you will be doing with the column, change the column to be an XML column.
If you need to do this one time, look at taking the value and converting it to XML, then you can operate on it like you would normally. (Here is a link on how to convert).