SQL XML query from column - sql

How to select file names from this kind of XML in a SQL Server column?
file name is in attribute VALUE only if high level tag is object with name File
like this
<Object NAME="File">
<Parameter ID="1" NAME="Name" VALUE="\\mysvr\fiels\readme1.txt" />
</Object>
This sub-hierarchy can be placed on any level of xml (see example below)
XML column can contain 0-N file names, I need list like this:
id, filename
--- ------------------------
1 \\mysvr\fiels\readme1.txt
1 \\mysvr\fiels\readme2.txt
2 \\mysvr\fiels\readme3.txt
2 \\mysvr\fiels\readme4.txt
Example of XML contents:
declare #t1 table
( id int,
x XML
)
insert into #t1 (id, x)
select 1,N'<root name="name" id="12">
<class1>
<Object NAME="File">
<Parameter ID="1" NAME="Name" VALUE="\\mysvr\fiels\readme1.txt" />
</Object>
</class1>
<class1>
<subclass1>
<Object NAME="File">
<Parameter ID="10" NAME="Name" VALUE="\\mysvr\fiels\readme2.txt" />
</Object>
<Object NAME="bitmap">
<Parameter ID="11" NAME="my1" VALUE="bmp" />
</Object>
</subclass1>
</class1>
</root>'
union
select 2,N'<root name="name" id="12">
<class1>
<Object NAME="File">
<Parameter ID="13" NAME="Name" VALUE="\\mysvr\fiels\readme3.txt" />
</Object>
<Object NAME="Font">
<Parameter ID="22" NAME="Tahoma" VALUE="11" />
</Object>
</class1>
<class1>
<subclass1>
<Object NAME="File">
<Parameter ID="14" NAME="Name" VALUE="\\mysvr\fiels\readme4.txt" />
</Object>
</subclass1>
</class1>
</root>'

Try this:
SELECT
id,
Filename = ObjPrm.value('#VALUE', 'varchar(100)')
FROM #t1
CROSS APPLY x.nodes('//Object[#NAME="File"]/Parameter') AS Tbl(ObjPrm)
Gives me an output of:

To do this you can do the following.
Define a string of the specific details you want to display.
You want to display id and Name so your string will look something like this.
String holder = "#id# -- #VALUE#"
Then you search through that whole string for the values you have between the two '#' signs.
When you find them, just do a search for the value inside the Quotation marks, and display them.

Related

Querying XML data stored in SQL Server column

My table is XMLData with an XML column XMLField.
The data in the column looks like this:
<table>
<id>{9ebef1ed-51f6-4160-b342-40fd1bf311c5}</id>
<rows>
<row>
<columns>
<column name="Batch" value="Test Batch 123" type="System.String" />
<column name="PartNo" value="Sample123" type="System.String" />
<column name="Note" value="Slight Color Variants" type="System.String" />
<column name="ShipDate" value="05-August-2018" type="System.DateTime" />
<column name="Qty" value="2" type="System.Int32" />
<column name="DefaultKey" value="1" type="System.Int32" />
</columns>
</row>
<row>
<columns>
<column name="Batch" value="Second Batch" type="System.String" />
<column name="PartNo" value="SampleXyz" type="System.String" />
<column name="Note" value="Release Date TBD" type="System.String" />
<column name="ShipDate" value="01-September-2018" type="System.DateTime" />
<column name="Qty" value="1" type="System.Int32" />
<column name="DefaultKey" value="2" type="System.Int32" />
</columns>
</row>
</rows>
<key>DefaultKey</key>
<total>0</total>
<data />
<parameters />
</table>
I would like to query Batch, PartNo, Note, ShipDate, Qty, DefaultKey and retrieve the values.
Thank you
Try something like this:
SELECT
Batch = XC.value('(column[#name="Batch"]/#value)[1]', 'varchar(50)'),
PartNo = XC.value('(column[#name="PartNo"]/#value)[1]', 'varchar(50)'),
Note = XC.value('(column[#name="Note"]/#value)[1]', 'varchar(50)'),
ShipDate = XC.value('(column[#name="ShipDate"]/#value)[1]', 'varchar(50)'),
Qty = XC.value('(column[#name="Qty"]/#value)[1]', 'int'),
DefaultKey = XC.value('(column[#name="DefaultKey"]/#value)[1]', 'int')
FROM
dbo.XmlData
CROSS APPLY
XmlField.nodes('/table/rows/row/columns') AS XT(XC)
It basically takes the XmlField column's XML, and gets a "virtual" table of XML fragments according to the XPath in the .nodes() expression. From there, it reaches into those XML fragments returned, and pulls out the individual values you're interested in.

Extract multiple date strings from a single varchar(MAX) column SQL Server

I've inherited a report spec subsystem that needs to be tweaked. The mission is to add a date column to the tReports table, and populate it with the CreateDate that is (supposed to be) contained in the XML Code Spec. The problem is that some of the older reports don't have the CREATEDATE attribute, or as in one example below, the XML is valid but poorly formed, and the CREATEDATE cannot be retrieved using the xQuery that works for most of the other reports. Since I don't have an explicit creation date included in the spec, I'm using interpolation to estimate a reasonable date. One factor of the interpolation is to look at the date strings contained in the report spec--some will be useful, others not.
There are too many reports (over 1,200) to visually skim each report spec for date strings. These date strings can appear in any location in the report spec, and there are a very large number of combinations of elements and attributes that can contain a date string.
The ideal solution would be a listing of the reportID's and the date string ready to use in an UPDATE, but because date format varies (m/d/yy, mm/dd/yy, m/dd/yy ...) I'd be grateful to get a vew spurious characters surrounding the date string that I could clean up later.
All the date strings will be from 2000 or later, so the search string I'v been using is '/20' which has provided good results.
I've looked at many sites that discuss this kind of issue, and found only one solution by Mikael Eriksson that is something like what I'm describing, but I can't make it work after several hours of playing with it. How to extract multiple strings from single rows in SQL Server
Is there a way, without using a cursor nor WHILE loop, to extract these embedded dates?
-- Some representative data: (I'm using SQL Server 2008 R2)
CREATE TABLE #ReportSpecs (ReportID INT, ReportSpec VARCHAR(MAX))
INSERT INTO #ReportSpecs
( ReportID, ReportSpec )
VALUES
(136,
'<ReportID>136</ReportID>
<EmpIDCreator>23816</EmpIDCreator>
<EmpName>Blanc, Melvin J</EmpName>
<ReportType>0</ReportType>
<ReportName>PSST Sys Spec</ReportName>
<ReportData>
<REPORT>
<COLUMNS>
<Column Name="JobNumber" Position="1" />
<Column Name="TaskType" Position="2" />
<Column Name="Assignees" Position="3" />
<Column NAME="JobDueDate" Position="4" />
<Column Name="ReferenceNumber" Position="5" />
<Column Name="Deliverable" Position="6" />
<Column Name="Priority" Position="7" />
</COLUMNS>
<FILTERS>
<FILTER NAME="TYPE" VALUE="To_Me" />
<FILTER NAME="Status" VALUE="All" />
<FILTER NAME="DateOptions" VALUE="DateRange" From="8/16/2002" To="8/23/2002" />
<FILTER NAME="FromDate" VALUE="8/16/2002" />
<FILTER NAME="ToDate" VALUE="8/23/2002" />
<FILTER NAME="Role" VALUE="All" />
</FILTERS>
<parameters>
<PARAMETER NAME="#Cascading" TYPE="integer" VALUE="0" />
<PARAMETER NAME="#EmpID" SYSTEM="true" TYPE="integer" VALUE="#Request.EmployeeIDAlias#" />
<PARAMETER NAME="#FromOrgs" TYPE="varchar(250)" VALUE="" />
<PARAMETER NAME="#ToOrgs" TYPE="varchar(250)" VALUE="" />
</parameters>
<NAME>PSST Sys Spec</NAME>
<OWNER>
<ID>23816</ID>
</OWNER>
<source id="8" useinternalid="True" />
</REPORT>
</ReportData>'),
(311,
'<ReportID>311</ReportID>
<EmpIDCreator>7162</EmpIDCreator>
<EmpName>Potter, Harry J</EmpName>
<ReportType>0</ReportType>
<ReportName>CPVC Synch Test</ReportName>
<ReportData>
<REPORT>
<COLUMNS>
<Column Name="JobNumber" Position="1" />
<Column Name="TaskType" Position="2" />
<Column Name="Subject" Position="3" />
<Column Name="CurrentAssignee" Position="4" />
<Column NAME="JobDueDate" Position="5" />
<Column Name="Deliverable" Position="6" />
<Column Name="Category" Position="7" />
<Column Name="Priority" Position="8" />
</COLUMNS>
<FILTERS>
<FILTER NAME="TYPE" VALUE="By_Orgs_6098,By_Orgs_6123" />
<FILTER NAME="Status" VALUE="Open" />
<FILTER NAME="DateOptions" VALUE="DateRange" From="3/25/2002" To="4/4/2002" />
<FILTER NAME="ReviewFromDate" VALUE="3/25/2002" />
<FILTER NAME="ReviewToDate" VALUE="4/4/2002" />
<FILTER NAME="Role" VALUE="All" />
</FILTERS>
<parameters>
<PARAMETER NAME="#Act" TYPE="integer" VALUE="0" />
<PARAMETER NAME="#MgrID" SYSTEM="true" TYPE="integer" VALUE="#Request.EmployeeIDAlias#" />
<PARAMETER NAME="#MgrIDActing" TYPE="integer" VALUE="" />
<PARAMETER NAME="#FromDept" TYPE="varchar(250)" VALUE="" />
<PARAMETER NAME="#FromEmp" TYPE="varchar(250)" VALUE="" />
<PARAMETER NAME="#ToDept" TYPE="varchar(250)" VALUE="" />
</parameters>
<NAME>CPVC Synch Test</NAME>
<OWNER>
<ID>7162</ID>
</OWNER>
<source id="17" useinternalid="True" />
</REPORT>
</ReportData>'),
(1131,
'<ReportID>1131</ReportID>
<EmpIDCreator>13185</EmpIDCreator>
<EmpName>Reed, Alan</EmpName>
<ReportType>0</ReportType>
<ReportName>
''"><script>alert(''hello'')</script>
</ReportName>
<ReportData>
<Report NAME="''">
<script>alert(''hello'')</script>" CREATEDATE="12/7/2009">
<DESCRIPTION>sfasf</DESCRIPTION>
<OWNER ID="13185"/>
<SOURCE ID="1" USEINTERNALID="TRUE"/>
<COLUMNS>
<COLUMN NAME="JobNumber" POSITION="1" SORTORDER="asc"/>
</COLUMNS>
<FILTERS>
<FILTER NAME="TYPE" VALUE="By_Me,To_Me" />
<FILTER NAME="ASGSTATUS" VALUE="Open" />
<FILTER NAME="DATEOPTIONS" VALUE="All" />
<FILTER NAME="STATUS" VALUE="Open" />
<FILTER NAME="ASGDATEOPTIONS" VALUE="All" />
<FILTER NAME="ROLE" VALUE="All" />
</FILTERS>
<PARAMETERS>
<PARAMETER NAME="#Me" TYPE="integer" VALUE="3" />
<PARAMETER NAME="#FromCost" TYPE="varchar(250)" VALUE=""/>
<PARAMETER NAME="#ToCost" TYPE="varchar(250)" VALUE="" />
</PARAMETERS>
<ADVANCEDSORT SortByA="JobNumber" SortOrderA="asc" SortByB="" SortOrderB="" SortByC="" SortOrderC="" />
</Report>
</ReportData>');
/*
Desired Output (A DISTINCT list would be better, but just getting this output would be GREAT.)
ReportID DateString
-------- ----------
136 8/16/2002
136 8/23/2002
136 8/16/2002
136 8/23/2002
311 3/25/2002
311 4/4/2002
311 3/25/2002
311 4/4/2002
1131 12/7/2009
*/
DROP TABLE #ReportSpecs
Thanks for your time.
select R.ReportID,
D.V as DateString
from #ReportSpecs as R
cross apply (select cast(R.ReportSpec as xml)) as X(R)
cross apply X.R.nodes('//#*, //*/text()') as T(X)
cross apply (select T.X.value('.', 'varchar(max)')) as D(V)
where charindex('/20', D.V) > 0
Result:
ReportID DateString
----------- --------------------------
136 8/16/2002
136 8/23/2002
136 8/16/2002
136 8/23/2002
311 3/25/2002
311 4/4/2002
311 3/25/2002
311 4/4/2002
1131 " CREATEDATE="12/7/2009">

How to make a dynamic xPath and execute it?

I collect string to xpath
<property xmlns:t="https://services" name="xPathElemet" expression="fn:concat(//t:SNILS/, $func:element)"/>
and I want to run this xpath and write the value of a Property
<property name="KEY" expression="get-property('xPathElemet')"/>
but receive only collected a string
how to xpath of the Property?
example code sequence :
<iterate continueParent="true" expression="//t:Employee">
<target>
<sequence>
<call-template target="save_element">
<with-param name="key_element" value="Name"/>
</call-template>
</sequence>
</target>
</iterate>
example code template :
<template xmlns="http://ws.apache.org/ns/synapse" name="save_element">
<parameter name="key_element"/> <!--example: "Name"-->
<sequence>
<property name="KEY" expression="fn:concat(//t:Employee/t:SNILS, ':' ,$func:key_element)" scope="default"
type="STRING"/> <!--example: "111-111-111-1:Name"-->
<property name="xPathElemet" expression="fn:concat('//t:Employee/t:', $func:element)"/> <!--example: "//t:Employee/t:Name"-->
<property name="VALUE" expression="get-property('xPathElemet')" scope="default" type="STRING"/> <!--example: Den (Now it does not work)-->
<dbreport>
<connection>
<pool>
<seetings/>
</pool>
</connection>
<statement>
<sql>
<![CDATA[insert into cache( key , value ) values (?, ?);]]></sql> <!--insert new line where key = "111-111-111-1:Name" and value = "Den"-->
<parameter expression="get-property('KEY')" type="VARCHAR"/>
<parameter expression="get-property('VALUE')" type="VARCHAR"/>
</statement>
</dbreport>
</sequence>
</template>
example xml:
<Employees xmlns="https://services">
<Employee>
<SNILS>111-111-111-1</SNILS>
<Name>Den</Name>
</Employee>
<Employee>
<SNILS>111-111-111-2</SNILS>
<Name>Elena</Name>
</Employee>
</Employees>
Use evaluate
In your case:
<property xmlns:t="https://services" name="xPathElemet" expression="fn:concat(//t:SNILS/, $func:element)"/>
<property name="KEY" expression="evaluate(get-property('xPathElemet'))"/>
You can find more infomation in this blog.
Please try the following and see if it works
<property xmlns:t="https://services" name="xPathElemet" expression="fn:concat(//t:SNILS/, $func:element)"/>
<property xmlns:t="https://services" name="xPathfull" expression="fn:concat(get-property('xPathElemet'),'/text()')"/>
<property name="KEY" expression="get-property('xPathfull')"/>
What was missing from your code was the /text() which refer to the parameters of the given xpath. Please try this

SQL Server XML query: how to select values?

How to select file names from xml like this, i.e.
I need only names:
c:\temp\f1.txt
c:\temp\f2.txt
XML like this:
<root name="name" id="12">
<class1>
<file name="c:\temp\f1.txt">
</class1>
<class1>
<subclass1>
<file name="c:\temp\f2.txt">
</subclass1>
</class1>
</root>
declare #XML xml
set #XML = '
<root name="name" id="12">
<class1>
<file name="c:\temp\f1.txt"/>
</class1>
<class1>
<subclass1>
<file name="c:\temp\f2.txt"/>
</subclass1>
</class1>
</root>'
select T.N.value('#name', 'nvarchar(100)') as FileName
from #XML.nodes('//file') as T(N)

sp_xml_preparedocument go with error "Only one top level element is allowed in an XML document"

I'am trying to execute sp_xml_preparedocument and geting error "Only one top level element is allowed in an XML document"
my T-SQL commands:
DECLARE #aa XML
DECLARE #idoc int
SET #aa =(select * from db_name for xml auto, xmldata)
#aa now is
<Schema xmlns="urn:schemas-microsoft-com:xml-data" xmlns:dt="urn:schemas-microsoft-com:datatypes" name="Schema7">
<ElementType name="Person" content="empty" model="closed">
<AttributeType name="preson_id" dt:type="i4" />
<AttributeType name="Name" dt:type="string" />
<AttributeType name="Surname" dt:type="string" />
<AttributeType name="guid" dt:type="uuid" />
<AttributeType name="version" dt:type="bin.base64" />
<attribute type="preson_id" />
<attribute type="Name" />
<attribute type="Surname" />
<attribute type="guid" />
<attribute type="version" />
</ElementType>
</Schema>
<Person xmlns="x-schema:#Schema7" preson_id="1" Name="Иван" Surname="Иванов" guid="2E739E87-3CA4-4ED8-ADD0-8B59957668B8" version="AAAAAAAAB9E=" />
<Person xmlns="x-schema:#Schema7" preson_id="2" Name="Николай" Surname="Николаев" guid="BDC41C59-D70F-4B70-954E-4918B9516AF8" version="AAAAAAAAB9I=" />
<Person xmlns="x-schema:#Schema7" preson_id="3" Name="Максим" Surname="Максимов" guid="740E57F3-56BA-48B8-92AF-978D7B1D2712" version="AAAAAAAAB9M=" />
EXEC sp_xml_preparedocument #idoc OUTPUT, #aa
The XML parse error 0xc00ce555 occurred on line number 1, near the XML text ""
Msg 6602, Level 16, State 2, Procedure sp_xml_preparedocument, Line 1
The error description is 'Only one top level element is allowed in an XML document
I'am new in this, and i need help)))
An one more question - How parse timestamp type?
if i use
SET #aa =(select * from db_name for xml elements, root('root'), type)
sp_xml_preparedocument works fine, OPENXML returns all values of my db_table, but timestamp values looks not the same as were..
Sorry for my bad English
SELECT #aa returns
<Schema xmlns="urn:schemas-microsoft-com:xml-data" xmlns:dt="urn:schemas-microsoft-com:datatypes" name="Schema7">
<ElementType name="Person" content="empty" model="closed">
<AttributeType name="preson_id" dt:type="i4" />
<AttributeType name="Name" dt:type="string" />
<AttributeType name="Surname" dt:type="string" />
<AttributeType name="guid" dt:type="uuid" />
<AttributeType name="version" dt:type="bin.base64" />
<attribute type="preson_id" />
<attribute type="Name" />
<attribute type="Surname" />
<attribute type="guid" />
<attribute type="version" />
</ElementType>
</Schema>
<Person xmlns="x-schema:#Schema7" preson_id="1" Name="Иван" Surname="Иванов" guid="2E739E87-3CA4-4ED8-ADD0-8B59957668B8" version="AAAAAAAAB9E=" />
<Person xmlns="x-schema:#Schema7" preson_id="2" Name="Николай" Surname="Николаев" guid="BDC41C59-D70F-4B70-954E-4918B9516AF8" version="AAAAAAAAB9I=" />
<Person xmlns="x-schema:#Schema7" preson_id="3" Name="Максим" Surname="Максимов" guid="740E57F3-56BA-48B8-92AF-978D7B1D2712" version="AAAAAAAAB9M=" />
An XML document must have one root element only - see W3C specification.
Thus in you case if Schema is the root element you cannot add the Person elements at the end
Make sure that there is no duplicate entries for the record that you are trying to get