SQL Server XML query: how to select values? - sql

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)

Related

replace XML variable in sql [duplicate]

This question already has answers here:
Updating SQL Server XML node
(2 answers)
Closed 4 years ago.
How do I replace the variable value of xml in sql? I need to change the values of ID and Text.
Sample XML
<Values>
<ValueList>
<Entry key="Num" type="Values">
<value ID="1" Text="One" />
</Entry>
<Entry key="Name" type="Values">
<value ID="2" Text="two" />
</Entry>
</ValueList>
</Values>
You can modified the ID value like following. Here I am updating ID="1" to "111", similarly you can change the text for a specific text using modify.
DECLARE #XML XML
SET #XML= '<Values> <ValueList> <Entry key="Num" type="Values"> <value ID="1" Text="One" /> </Entry> <Entry key="Name" type="Values"> <value ID="2" Text="two" /> </Entry> </ValueList> </Values>'
SET #XML.modify('replace value of (Values/ValueList/Entry/value[#ID eq ("1")]/#ID)[1] with ("1111")')
select #XML
If you want to use variables, it can be achieved like following.
DECLARE #XML XML
Declare #IDTOReplace VARCHAR(5)='1'
DECLARE #IDWithReplace VARCHAR(5) = '111'
SET #XML= '<Values> <ValueList> <Entry key="Num" type="Values"> <value ID="1" Text="One" /> </Entry> <Entry key="Name" type="Values"> <value ID="2" Text="two" /> </Entry> </ValueList> </Values>'
SET #XML.modify('replace value of (Values/ValueList/Entry/value[#ID eq sql:variable("#IDTOReplace")]/#ID)[1] with sql:variable("#IDWithReplace")')
select #XML
If you want to change the Text based on some Id, it can be achieved like following.
DECLARE #XML XML
Declare #IDTOReplace VARCHAR(5)='1'
DECLARE #TextToReplace VARCHAR(100) = 'NewText'
SET #XML= '<Values> <ValueList> <Entry key="Num" type="Values"> <value ID="1" Text="One" /> </Entry> <Entry key="Name" type="Values"> <value ID="2" Text="two" /> </Entry> </ValueList> </Values>'
SET #XML.modify('replace value of (Values/ValueList/Entry/value[#ID eq sql:variable("#IDTOReplace")]/#Text)[1] with sql:variable("#TextToReplace")')
select #XML

Import XML to SQL

Sorry to put one more post regarding this topic, but I am desperate trying to import this xml to the database without any success.
This is the xml:
<session xmlns="http://winscp.net/schema/session/1.0" start="2014-11-03T17:23:22.376Z">
<ls>
<destination value="/Output" />
<files>
<file>
<filename value="." />
<type value="d" />
<modification value="2014-11-03T12:17:58.000Z" />
<permissions value="rwxr-sr-x" />
</file>
<file>
<filename value="7215_SG.csv" />
<type value="-" />
<size value="1584161" />
<modification value="2014-11-03T12:06:46.000Z" />
<permissions value="rw-r--r--" />
</file>
<file>
<filename value="6171_SG.csv" />
<type value="-" />
<size value="2298481" />
<modification value="2014-11-03T12:05:13.000Z" />
<permissions value="rw-r--r--" />
</file>
</files>
<result success="true" />
</ls>
</session>
And this is the sql statement to import the xml:
SELECT
xmldata.value('(./filename/#value)[1]', 'NVARCHAR(50)') AS szFilename,
xmldata.value('(./type/#value)[1]', 'NVARCHAR(50)') AS szType,
xmldata.value('(./size/#value)[1]', 'NVARCHAR(50)') AS szSize,
xmldata.value('(./modification/#value)[1]', 'NVARCHAR(50)') AS szModification,
xmldata.value('(./permissions/#value)[1]', 'NVARCHAR(50)') AS szPermissions
FROM
(SELECT CAST(x AS XML)
FROM OPENROWSET(BULK 'd:\temp\Test\log.xml',
SINGLE_BLOB) AS T(x)) AS T(x)
CROSS APPLY
x.nodes('//session/ls/files/file') AS X(xmldata);
Can you help me and tell me what am I doing wrong?
Thanks in advance!
You just simply need to respect the XML namespace that's defined on your XML root node!
<session xmlns="http://winscp.net/schema/session/1.0"
********************************************
To accommodate this XML namespace, you need to define in in your XQuery - best approach in my opinion is by using the WITH XMLNAMESPACES statement:
;WITH XMLNAMESPACES(DEFAULT 'http://winscp.net/schema/session/1.0')
SELECT
xmldata.value('(./filename/#value)[1]', 'NVARCHAR(50)') AS szFilename,
xmldata.value('(./type/#value)[1]', 'NVARCHAR(50)') AS szType,
xmldata.value('(./size/#value)[1]', 'NVARCHAR(50)') AS szSize,
xmldata.value('(./modification/#value)[1]', 'NVARCHAR(50)') AS szModification,
xmldata.value('(./permissions/#value)[1]', 'NVARCHAR(50)') AS szPermissions
FROM
(SELECT CAST(x AS XML)
FROM OPENROWSET(BULK 'd:\temp\Test\log.xml', SINGLE_BLOB) AS T(x)) AS T(x)
CROSS APPLY
x.nodes('//session/ls/files/file') AS X(xmldata);

SQL XML query from column

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.

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

Problem with xml select in tsql - can't seem to orgenize multi nodes in the right order

this is my code, i am trying to make a simple 3 nodes select in XML and it is not working, i am getting the parent, the second nodes (all of them) and then the third nodes (all of them) (categories->category(all)->products(all) and not in the right order (categories->category->all products for that category)
select 1 as tag,
null as parent,
null as [Categories!1],
null as [Category!2!ID],
null as [Category!2!Name],
null as [Product!3!ID],
null as [Product!3!Name],
null as [Product!3!Price]
union all
select 2 as tag,
1 as parent,
null,
CategoryID,
CategoryName,
NULL,
NULL,
NULL
from dbo.Categories
union all
select 3 as tag,
2 as parent,
null,
null,
null,
ProductID,
ProductName,
UnitPrice
from dbo.Products
where CategoryID=CategoryID
for xml explicit
If any one has an idea what am i doing wrong it would be great.
Thank you,
Erez
SQL Server 2005 and up have a very powerful new command - FOR XML PATH - which is a lot easier to use than the FOR XML EXPLICIT of olden days.
I don't know what exactly you want, but you could do something like:
SELECT
cat.CategoryID AS '#CategoryID',
cat.CategoryName AS 'Category/Name',
pr.ProductID AS '#ProductID',
pr.ProductName 'Product/Name',
pr.UnitPrice
FROM
dbo.Categories cat
INNER JOIN
dbo.Products pr ON cat.CategoryID = pr.CategoryID
FOR XML PATH('ProductCategory'), ROOT('Root')
This should give you something like:
<Root>
<ProductCategory CategoryID="5" ProductID="66">
<Category>
<Name>YourCategory Nr. 5</Name>
</Category>
<Product>
<Name>Your Product Nr. 66</Name>
</Product>
<UnitPrice>50.50</UnitPrice>
</ProductCategory>
</Root>
See some of those resources for more information on FOR XML PATH:
What's new in FOR XML in Microsoft SQL Server 2005
Using XML Serialization with SQL's FOR XML PATH
FOR XML PATH - a new mode in FOR XML in SQL Server 2005
Marc
UPDATE: ok, now that we know what you really want, I can provide the right answer :-)
SELECT
cat.CategoryID AS '#ID',
cat.CategoryName AS '#Name',
(SELECT
pr.ProductID AS '#ID',
pr.ProductName AS '#Name',
pr.UnitPrice AS '#Price'
FROM
dbo.T_Product pr
WHERE
cat.CategoryID = pr.CategoryID
FOR XML PATH('product'), TYPE
)
FROM
dbo.Categories cat
FOR XML PATH('category'), ROOT('Categories')
That gives me the output (from Northwind):
<Categories>
<category ID="1" Name="Beverages">
<product ID="1" Name="Chai" Price="18.0000" />
<product ID="2" Name="Chang" Price="19.0000" />
<product ID="24" Name="Guaraná Fantástica" Price="4.5000" />
<product ID="34" Name="Sasquatch Ale" Price="14.0000" />
<product ID="35" Name="Steeleye Stout" Price="18.0000" />
<product ID="38" Name="Côte de Blaye" Price="263.5000" />
<product ID="39" Name="Chartreuse verte" Price="18.0000" />
<product ID="43" Name="Ipoh Coffee" Price="46.0000" />
<product ID="67" Name="Laughing Lumberjack Lager" Price="14.0000" />
<product ID="70" Name="Outback Lager" Price="15.0000" />
<product ID="75" Name="Rhönbräu Klosterbier" Price="7.7500" />
<product ID="76" Name="Lakkalikööri" Price="18.0000" />
</category>
<category ID="2" Name="Condiments">
<product ID="3" Name="Aniseed Syrup" Price="10.0000" />
<product ID="4" Name="Chef Anton's Cajun Seasoning" Price="22.0000" />
<product ID="5" Name="Chef Anton's Gumbo Mix" Price="21.3500" />
<product ID="6" Name="Grandma's Boysenberry Spread" Price="25.0000" />
<product ID="8" Name="Northwoods Cranberry Sauce" Price="40.0000" />
<product ID="15" Name="Genen Shouyu" Price="15.5000" />
<product ID="44" Name="Gula Malacca" Price="19.4500" />
10x, but this is not what i am looking for.
In your answer u have 2 nodes. the parent(root) and 1 chile (ProductCategory) all the rest are attributes of the child node, not a new node under the child node.
what i am looking for is this
<Categories>
<category ID="2" Name="chuki">
<product ID="1" Name="chukchuk" Price="20" />
<product ID="2" Name="mhukmhuk" Price="20" />
<product ID="3" Name="ChakChak" Price="20" />
.......
</category>
<category ID="1" Name="Chuki">
<product ID="4" Name="lllll" Price="20" />
<product ID="5" Name="hhhhhh" Price="20" />
<product ID="1" Name="ChukChuk" Price="20" />
........
</category>
........
</categories>