I am using the below query to select the values of XML from attributes ad elements of the XML file but I am not able to read the seq, id, reported dated attributes from XML page
so any one please suggest How to get values of attributes using this Query.
select a_node.value('(./text())[1]', 'var char(50)') AS c_val,
c1_node.value('(./text())[1]', 'var char(50)') AS c_val 2,
ca_node.value('(./text())[1]', 'var char(50)') AS c_val3,
d_node.value('(./text())[1]', 'var char(50)') ,
e_node.value('(./text())[1]', 'varchar(50)') ,
f_node.value('(./text())[1]', 'var char(50)')
FROM #xmlData.nodes('/Reports/x:InquiryResponse/x:ReportData/x:AccountDetails/x:Account') AS b(b_node)
outer APPLY b.b_node.nodes('./x:primarykey') AS pK_InquiryResponse (a_node)
outer APPLY b.b_node.nodes('./x:seq') AS CustomerCode (c1_node)
outer APPLY b.b_node.nodes('./x:id') AS amount (ca_node)
outer APPLY b.b_node.nodes('./x:ReportedDate') AS CustRefField (d_node)
outer APPLY b.b_node.nodes('./x:AccountNumber') AS ReportOrderNO (e_node)
outer apply b.b_node.nodes('./x:CurrentBalance') as additional_id (f_node);
Edit: Xml Snippets Provided in Comments
<sch:Account seq="2" id="345778174" ReportedDate="2014-01-01">
<sch:AccountNumber>TSTC1595</sch:AccountNumber>
<sch:CurrentBalance>0</sch:CurrentBalance>
<sch:Institution>Muthoot Fincorp Limited</sch:Institution>
<sch:PastDueAmount>0</sch:PastDueAmount>
<sch:DisbursedAmount>12000</sch:DisbursedAmount>
<sch:LoanCategory>JOG Group</sch:LoanCategory>
</sch:Account>
<sch:Account seq="2" id="345778174" ReportedDate="2014-01-01">
<sch:BranchIDMFI>THRISSUR ROAD</sch:BranchIDMFI>
<sch:KendraIDMFI>COSTCO/RECENT-107</sch:KendraIDMFI>
</sch:Account>
Parsing XQuery with an Xml Loose #Variable
Assuming an Xml document similar to this (viz with all the attributes on one element):
DECLARE #xmlData XML =
N'<Reports xmlns:x="http://foo">
<x:InquiryResponse>
<x:ReportData>
<x:AccountDetails>
<x:Account x:primarykey="pk" x:seq="sq" x:id="id"
x:ReportedDate="2014-01-01T00:00:00" />
</x:AccountDetails>
</x:ReportData>
</x:InquiryResponse>
</Reports>';
You can scrape the attributes out as follows:
WITH XMLNAMESPACES('http://foo' AS x)
select
Nodes.node.value('(#x:primarykey)[1]', 'varchar(50)') AS c_val,
Nodes.node.value('(#x:seq)[1]', 'varchar(50)') AS c_val2,
Nodes.node.value('(#x:id)[1]', 'varchar(50)') AS c_val3,
Nodes.node.value('(#x:ReportedDate)[1]', 'DATETIME') as someDateTime
FROM
#xmlData.nodes('/Reports/x:InquiryResponse/x:ReportData/x:AccountDetails/x:Account')
AS Nodes(node);
Attributes don't need text() as they are automatically strings
It is fairly unusual to have attributes in a namespace - drop the xmlns alias prefix if they aren't.
SqlFiddle here
Edit - Parsing Xml Column
Namespace dropped from the attributes
-Assumed that you have the data in a table, not a variable, hence the APPLY requirement. Note that OUTER APPLY will return nulls, e.g. useful only if you have rows with
empty Xml or missing Xml Elements. CROSS APPLY is the norm (viz
applying the xpath to each row selected on the LHS table)
Elements are accessed similar to attributes, just without #
WITH XMLNAMESPACES('http://foo' AS x)
select
Nodes.node.value('(#seq)[1]', 'varchar(50)') AS c_val2,
Nodes.node.value('(#id)[1]', 'varchar(50)') AS c_val3,
Nodes.node.value('(#ReportedDate)[1]', 'DATETIME') as someDateTime,
Nodes.node.value('(x:AccountNumber)[1]', 'VARCHAR(50)') as accountNumber
FROM
MyXmlData z
CROSS APPLY
z.XmlColumn.nodes('/Reports/x:InquiryResponse/x:ReportData/x:AccountDetails/x:Account')
AS Nodes(node);
Updated Fiddle
Edit Xml File off Disk
Here's the same thing for an xml file read from disk. Note that once you have the data in an XML variable (#MyXmlData) that you don't need to CROSS APPLY to anything - just supply xpath to select the appropriate node, and then scrape out the elements and attributes.
DECLARE #MyXmlData XML;
SET #MyXmlData =
( SELECT * FROM OPENROWSET ( BULK N'c:\temp\file3098.xml', SINGLE_CLOB ) AS MyXmlData );
-- Assuming all on the one element, no need for all the applies
-- attributes don't have a text axis (they are automatically strings
WITH XMLNAMESPACES('http://foo' AS x)
select
Nodes.node.value('(#seq)[1]', 'varchar(50)') AS c_val2,
Nodes.node.value('(#id)[1]', 'varchar(50)') AS c_val3,
Nodes.node.value('(#ReportedDate)[1]', 'DATETIME') as someDateTime,
Nodes.node.value('(x:AccountNumber)[1]', 'VARCHAR(50)') as accountNumber
FROM
#MyXmlData.nodes('/Reports/x:InquiryResponse/x:ReportData/x:AccountDetails/x:Account')
AS Nodes(node);
Related
I want to retrieve the XML value stored in PKDATA data field where name is inpatienttype want returns value 262784091 as inpatienttype
OUTPUT
A
B
Inpatientype
11,212
2587165
262784091
Dataset
Image
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:DataSet xmlns:ns2="http://www.test.com/t/cn/el">
<EnumObject>
<name>InpatientType</name>
<prompt>InpatientType</prompt>
<value>262784091</value>
<radiobutton>false</radiobutton>
</EnumObject>
<StringObject>
<name>xxx</name>
<prompt></prompt>
<value>/widget.jsp</value>
<width>99</width>
</StringObject>
</ns2:DataSet>
I used the following queries but didn't work
SELECT XMLQUERY(
'/EnumObject/name'
PASSING XMLTYPE(e.pkdata)
RETURNING CONTENT
) AS name
FROM EXTDATA as e
select x.*
from [dbo].[EXTRADATA] rt
cross join xmltable(
'/EnumObject/name'
passing xmltype(rt.packeddata)
columns name number path 'name/#value'
) x
Getting this error
Parse error at line: 3, column: 3: Incorrect syntax near 'PASSING'.
Can someone please help me here
In Microsoft SQL Server you can use XQuery via the nodes(), query() and value() functions.
If the source data involves custom XML namespaces you can also use with xmlnamespaces to namespace qualify the nodes of your XQuery, for example:
with xmlnamespaces (
'http://www.test.com/t/cn/el' as cnel
)
select
EnumObject.value('(./name/text())[1]', 'varchar(50)') as name,
EnumObject.value('(./prompt/text())[1]', 'varchar(50)') as prompt,
EnumObject.value('(./value/text())[1]', 'varchar(50)') as value
from dbo.TOCEXTRADATA
cross apply packeddata.nodes('/cnel:DataSet/EnumObject') p(EnumObject);
name
prompt
value
InpatientType
InpatientType
262784091
The following query avoids the custom namespace on the root node and returns an equivalent result:
select
EnumObject.value('(./name/text())[1]', 'varchar(50)') as name,
EnumObject.value('(./prompt/text())[1]', 'varchar(50)') as prompt,
EnumObject.value('(./value/text())[1]', 'varchar(50)') as value
from dbo.TOCEXTRADATA
cross apply packeddata.nodes('//EnumObject') p(EnumObject);
name
prompt
value
InpatientType
InpatientType
262784091
Edit: when the data type of the packeddata column isn't xml you'll need to cast it to the correct type. The two example queries above need to be modified in the following way:
with xmlnamespaces (
'http://www.test.com/t/cn/el' as cnel
)
select
EnumObject.value('(./name/text())[1]', 'varchar(50)') as name,
EnumObject.value('(./prompt/text())[1]', 'varchar(50)') as prompt,
EnumObject.value('(./value/text())[1]', 'varchar(50)') as value
from dbo.TOCEXTRADATA
outer apply ( select cast(packeddata as xml) as xmlData ) oa
cross apply xmlData.nodes('/cnel:DataSet/EnumObject') p(EnumObject);
select
EnumObject.value('(./name/text())[1]', 'varchar(50)') as name,
EnumObject.value('(./prompt/text())[1]', 'varchar(50)') as prompt,
EnumObject.value('(./value/text())[1]', 'varchar(50)') as value
from dbo.TOCEXTRADATA
outer apply ( select cast(packeddata as xml) as xmlData ) oa
cross apply xmlData.nodes('//EnumObject') p(EnumObject);
SELECT *
FROM #myHierarchy
FOR XML AUTO
Data is
<_x0040_myHierarchy element_id="1" parent_ID="1" NAME="itemCode" StringValue="Simmi" ValueType="string" />
I'm unable to load data in this query
SELECT #xml = dbo.ToXML(#myHierarchy);
SELECT
a.b.value('#ItemCode', 'varchar(20)') AS ItemCode
FROM
#xml.nodes('/root/_x0040_myHierarchy') a(b)
In this query, itemcode is blank. How can I load data using this query?
Your sample XML does not contain any attribute ItemCode - it has these attributes:
element_id
parent_ID
NAME
StringValue
ValueType
So which value do you really want to read out from the XML element?
Update: to retrieve the StringValue attribute, use this code:
SELECT
XC.value('#StringValue', 'varchar(50)')
FROM
#xml.nodes('/_x0040_myHierarchy') AS XT(XC)
If your XML contains a <root> ..... </root> root element, and multiple <_x0040_myHierarchy> elements inside, and you want to extract the one with #Name = 'itemCode' - then you need to use this SELECT:
SELECT
XC.value('#StringValue', 'varchar(50)')
FROM
#xml.nodes('/root/_x0040_myHierarchy') AS XT(XC)
WHERE
XC.value('#NAME', 'varchar(50)') = 'itemCode'
I have the below query I am trying to return distinct value from the second .value method.
Here is what I have tried. I tried adding 'distinct-values(.)' to return only distinct but it is still returning the same results as a normal '.' How can I select distinct values from just one column?
;WITH XMLNAMESPACES (default 'http://www.w3.org/2001/XMLSchema')
SELECT
a.value('.', 'NVARCHAR(50)') AS Visitor
, b.value('distinct-values(.)', 'NVARCHAR(50)') AS Sender
FROM XmlTable AS X
CROSS APPLY xmlDocument.nodes('Root/Visitors/Visitor') AS aa(a)
CROSS APPLY xmlDocument.nodes('Root/Senders/Sender') AS bb(b)
Here is the normal result
Here is whay I am trying to get
Xml Like this
<upx:Root xmlns:upx="http://www.w3.org/2001/XMLSchema">
<upx:Visitors>
<upx:Visitor>Visitor1</upx:Visitor>
<upx:Visitor>Visitor2</upx:Visitor>
</upx:Visitors>
<upx:Senders>
<upx:Sender>Sender1</upx:Sender>
</upx:Senders>
</upx:Root>
It is your cross apply with your nodes statement listed twice that is showing this problem. Do what you are doing with the 'nodes' syntax with a 'query' extension instead followed up by a 'value' extension to show what is in the xml directly from extension instead of relying on the nodes with a cross apply. The problem is you are not displaying to the audience where you get that Id from? Are you determining that at run time from the xml itself or joining yet to another table or having another part of the xml not present? What in essence that is happening with the nodes is it is cross applying and saying: "I have two vales in that node heirarchy here they are." Then you are cross applying again a different node and it is returning the same thing twice. You must be careful when using cross apply twice exactly what it is doing. I can show the differentiation but without how I know you are relating back to 1 (are you just hunting for it somehow for the int after visitor?) I don't know how to represent exactly what you are wanting.
EDIT: Okay it is what I thought then. Now my code may be longer than some and I will admit there may be an easier way to do this however I would do three things:
Keep your cross apply with nodes because nodes is useful in that it will repeat rows you need to count on. However I would add an artificial flag for the name you use for the node. Then I would union together two select statements using the nodes.
I would then use a nested select as a from statement and then determine row number with a windowed function based on the flags I just set.
I would then nest that again and then use the very same row number as the Id of the row number and then I would do some syntactic pivoting based on a max(case when) based on the flags I arbitrarily set.
I usually prefer cte's but since your XML namespace has a 'with' beginning and the first cte does as well I forgot how the syntax is to work around that. Nested Selects IMHO can get hairy when there are multiple so I choose CTE's usually but in this case I did a nested select inside of another nested select. I hope this helps:
declare #xml xml = '<upx:Root xmlns:upx="http://www.w3.org/2001/XMLSchema">
<upx:Visitors>
<upx:Visitor>Visitor1</upx:Visitor>
<upx:Visitor>Visitor2</upx:Visitor>
</upx:Visitors>
<upx:Senders>
<upx:Sender>Sender1</upx:Sender>
</upx:Senders>
</upx:Root>'
;
declare #Xmltable table ( xmlDocument xml);
insert into #XmlTable values (#xml);
WITH XMLNAMESPACES (default 'http://www.w3.org/2001/XMLSchema')
select
pos as Id
, max(case when Listing = 'Visitors' then Value end) as Visitors
, max(case when Listing = 'Senders' then Value end) as Senders
from
(
select
*
, row_number() over(partition by Listing order by Value) as pos
from
(
SELECT
'Visitors' as Listing
, a.value('.', 'NVARCHAR(50)') AS Value
FROM #XmlTable AS X
CROSS APPLY xmlDocument.nodes('Root/Visitors/Visitor') AS aa(a)
union
SELECT
'Senders'
, b.value('distinct-values(.)', 'NVARCHAR(50)') AS Sender
FROM #XmlTable AS X
CROSS APPLY xmlDocument.nodes('Root/Senders/Sender') AS bb(b)
) as u
) as listing
group by pos
source data looks comes from the following, freely available XML files describing major league baseball games.
http://gd2.mlb.com/components/game/mlb/year_2013/month_04/day_09/gid_2013_04_09_atlmlb_miamlb_1/inning/
I have created a SQL Server table that contains a row for every GamePK/inning, with an XML column named PBP. Each file in the folder above becomes a row in this table. The query below is my attempt to parse the XML into a record set. It works but is very slow for a large number of rows, and very repetitive - seems like there should be a better way to do this without the UNION clause. Any help in improving/optimizing is appreciated
select
i.GamePK
,inn.value('#num', 'int') as inning
,itop.value('1', 'int') as IsTop
,itop.value('#num', 'int') as abNum
,itop.value('#batter', 'int') as batter
-- clip
,itoppit.value('#des', 'varchar(32)') as pitdesc
,itoppit.value('#id', 'int') as seq
,itoppit.value('#type', 'varchar(8)') as pittype
-- clip
from tblInnings i
cross apply PBP.nodes('/inning') as inn(inn)
cross apply inn.nodes('top/atbat') as itop(itop)
cross apply itop.nodes('pitch') as itoppit(itoppit)
union
select
i.GamePK
,inn.value('#num', 'int') as inning
,ibot.value('0', 'int') as IsTop
,ibot.value('#num', 'int') as abNum
,ibot.value('#batter', 'int') as batter
-- clip
,ibotpit.value('#des', 'varchar(32)') as pitdesc
,ibotpit.value('#id', 'int') as seq
,ibotpit.value('#type', 'varchar(8)') as pittype
--clip
from tblInnings i
cross apply PBP.nodes('/inning') as inn(inn)
cross apply inn.nodes('bottom/atbat') as ibot(ibot)
cross apply ibot.nodes('pitch') as ibotpit(ibotpit)
If you're using a recent version of SQL Server, there's a new column data type (XML).
You can apply xpath to it, making querying the column much easier.
Instead of trying to store the XML as a string in your DB, I'd suggest you actually store it as XML, and treat it as XML.
There is a learning curve. You'll need to be familiar with XPATH, but it's not rocket science.
an example:
SELECT Id, PartitionMonth, EmailAddress, AcquisitionCodeId, FieldValues.value('
declare namespace s="http://domain.com/FieldValues.xsd";
data(/s:FieldValues/s:item/#value)[1]', 'varchar(200)')
FROM Leads.Leads WITH (NOLOCK)
WHERE Id = 190708
Another example retrieving values by key:
SELECT r.EmailAddress, ar.Ip, ar.DateLog,
ar.FieldValues.value('
declare namespace s="http://domain.com/FieldValues.xsd";
data(/s:FieldValues/s:item[#key="First Name"]/#value)[1]', 'varchar(20)') FirstName,
ar.FieldValues.value('
declare namespace s="http://domain.com/FieldValues.xsd";
data(/s:FieldValues/s:item[#key="Last Name"]/#value)[1]', 'varchar(20)') LastName
FROM Records.Records r WITH (NOLOCK)
JOIN Records.AcquisitionRecords ar WITH (NOLOCK) ON r.Id = ar.Id
WHERE ar.AcquisitionCodeId IN (19, 21, 30, 34, 36)
AND ar.DateLog BETWEEN '1-mar-09' AND '31-mar-09'
A good place to get started on XML in SQL Server
http://msdn.microsoft.com/en-US/library/ms189887(v=sql.90).aspx
How do I convert a string into an XML datatype so that I can query the data as XML:
For example (thanks to "mellamokb the Wise" who provided the original SQL for this)
The code below works fine if xmlstring is of the type XML (see DEMO)
select id, name
from Data
cross apply (
select Destination.value('data(#Name)', 'varchar(50)') as name
from [xmlstring].nodes('/Holidays/Summer/Regions/Destinations/Destination') D(Destination)
) Destinations(Name)
However, if xmlString is of type varchar I get an error even though I'm converting the string to XML (DEMO):
select id, name
from Data
cross apply (
select Destination.value('data(#Name)', 'varchar(50)') as name
from CONVERT(xml,[xmlstring]).nodes('/Holidays/Summer/Regions/Destinations/Destination') D(Destination)
) Destinations(Name)
You can do the cast it in one extra cross apply.
select id,
T.N.value('#Name', 'varchar(50)') as name
from Data
cross apply (select cast(xmlstring as xml)) as X(X)
cross apply X.X.nodes('/Holidays/Summer/Regions/Destinations/Destination') T(N)
SQL Fiddle
There might be performance issues with casting to XML. Have a look at this answer and this answer