Querying a table that contains an XML column - sql

I have a table that contains an xml column, my table looks like the following:
MyTable
Id(Pk, int,not null)
Name(varchar(50), not null)
Value(XML(.), not null)
The type of Value is XML
I've tried the following query and of course it is not working
/****** Script ******/
SELECT TOP 1000 [Id]
,[Name]
,[Value]
FROM [Value]
where Value like '%something%'
How can I get columns that contains something in their xml value

Would this work? I'm assuming you meant to select FROM MyTable, not from [Value]:
SELECT TOP 1000 [Id]
,[Name]
,[Value]
FROM [MyTable]
where CAST(Value AS VARCHAR(MAX)) like '%something%'

XML
<root>
<role>Alpha</role>
<role>Beta</role>
<role>Gamma</role>
</root>
select [Name] ,[Value]
from Value
where Value.value('(/root/role)[1]', 'varchar(max)') like '%Beta%'
also refer How can I query a value in SQL Server XML column

Related

Read XML data in SQL Server 2012

I want to read xml data in the xml file.
I have a table column consist with the xml data.
if i click on the xml file it will open in the Sql server Management studio.
xml file format shown below.
I want to read only NTDomainName, DatabaseName and ServerName and write that data in the another Table. Table format shown below
NTDomainName | DatabaseName | ServerName
----------
ABC | TestCube1 | SERXYZ
Try this:
declare #xml xml
set #xml = '<event><data name="NTUserName"><value>MyName</value></data><data name="NTDomainName"><value>DomainName</value></data><data name="ServerName"><value>ServerName</value></data></event>'
select [NTDomainName], [DatabaseName], [ServerName] from
(
select [name],[value] from (
select c.value('./#name', 'varchar(100)') [name], c.value('(./value)[1]', 'varchar(100)') [value]
from #xml.nodes('/event/data') as t(c)
) a where [name] in ('NTDomainName', 'DatabaseName', 'ServerName')
) x
pivot (
max(value) for [name] in ([NTDomainName], [DatabaseName], [ServerName])
) as [pivot_Name]
The most inner query will retrieve information from XML, one row for every name attribute value, that you want to retrieve. So, output of this query needs to be pivoted.
i think you look for this:
SELECT * FROM (
SELECT
CAST(f.x.query('data(#name)') as varchar(150)) as data_name,
CAST(f.x.query('data(value)') as varchar(150)) as data_value
FROM #xml.nodes('/event') as t(n)
CROSS APPLY t.n.nodes('data') as f(x)) X
PIVOT (MAX(data_value) FOR data_name IN (NTDomainName, DatabaseName, ServerName)) as pvt
If you do not want to use PIVOT:
DECLARE #DataSource TABLE
(
[ID] TINYINT IDENTITY(1,1)
,[XML] XML
);
INSERT INTO #DataSource ([XML])
VALUES ('<event><data name="SessionID">S1</data><data name="NTUserName">User1</data><data name="DatabaseName">DB1</data><data name="ServerName">SN1</data></event>')
,('<event><data name="SessionID">S1</data><data name="NTUserName">User2</data><data name="DatabaseName">DB2</data><data name="ServerName">SN2</data></event>');
SELECT [ID]
,MAX(CASE wHEN C.value('(./#name)[1]', 'varchar(50)') = 'NTUserName' THEN C.value('(.)[1]', 'varchar(50)') END) AS [NTUserName]
,MAX(CASE wHEN C.value('(./#name)[1]', 'varchar(50)') = 'DatabaseName' THEN C.value('(.)[1]', 'varchar(50)') END) AS [DatabaseName]
,MAX(CASE wHEN C.value('(./#name)[1]', 'varchar(50)') = 'ServerName' THEN C.value('(.)[1]', 'varchar(50)') END) AS [ServerName]
FROM #DataSource
CROSS APPLY [XML].nodes('event/data[#name = "NTUserName" or #name = "DatabaseName" or #name = "ServerName"]') T(c)
GROUP BY [ID];

SQL Server Populate XML Variable from VARCHAR rows

I have a single column table in SQL Server.
This column hold each row of an XML document.
Sample table :
Column
---------------
Row1: <ROOT>
Row2: <Name>name1</Name>
Row3: </ROOT>
Column data type is nvarchar(max)
I want to do:
DECLARE #RES_XML XML
SET #XML = Set from table above
How can I sum up all rows of the table above and populate #RES_XML?
Note: when concatenated; all data in the table exceeds nvarchar(max) limit.
In general, easiest way to concatenate values into variable is
declare #res nvarchar(max)
select #res = isnull(#res, '') + [Column]
from <table above>
select cast(#res as xml)
Of course, order of concatenation in this query is not defined (but there is a trick to check if order is maintained)
I am as surprised by your exceeding the limit of nvarchar(max) columns as Marc is, but maybe you have column limit settings in your database set-up that you can't change. Here's how I would do it, and I'm assuming there is some column that let's you order the tags in the appropriate order, you cannot rely on the order in which the database decided to store and retrieve the rows.
declare #t table (
id int,
x nvarchar(max)
)
insert into #t
select 1, '<ROOT>' union all
select 2, '<Name>name1</Name>' union all
select 3, '</ROOT>'
DECLARE #RES_XML XML
select #RES_XML = cast((
select x
from #t
order by id
for xml path(''), type
).value('.', 'nvarchar(max)') as xml)

Xml select query xpath is slow

My XML structure:
<Items>
<Item>
<guid>FC550573-7171-997F-752D-8D65590CBFD6</guid>
<Objects>
<Object>
<type>0</type>
<guid>E10D9DA9-2C8D-8024-2F07-DF21395811BF</guid>
</Object>
<Object>
<type>0</type>
<guid>D8338400-35C7-781E-A039-C0FDDF80714A</guid>
</Object>
</Objects>
</Item>
</Items>
When filling the Objects Table:
CREATE TABLE [dbo].[Objects](
[item_guid] [varchar](36) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[type] [int] NOT NULL,
[guid] [varchar](36) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL
) ON [PRIMARY]
Using the Query:
INSERT INTO [dbname].[dbo].[Objects]
([item_guid]
,[type]
,[guid])
SELECT
X.source.query('../../guid').value('.','VARCHAR(36)') as item_guid,
X.source.query('type').value('.','INT') as type,
X.source.query('guid').value('.','VARCHAR(36)') as guid
FROM(
Select xmldata from XmlFiles where fullpath=#fp
) AS T(x)
CROSS APPLY x.nodes('Items/Item/Objects/Object') As X(source)
This line is making the query VERY slow:
X.source.query('../../guid').value('.','VARCHAR(36)') as item_guid
What is the proper approach here?
Using /text() to get the value is good for performance on untyped XML. It can also be bad to use the parent axis ../.. (as #marc_s suggested).
Here is a version with a extra cross apply and /text() to get the values.
Try this:
select T2.N.value('(guid/text())[1]', 'uniqueidentifier') as item_guid,
T3.N.value('(type/text())[1]', 'int') as type,
T3.N.value('(guid/text())[1]', 'uniqueidentifier') as guid
from (SELECT xmldata FROM dbo.XmlFiles WHERE fullpath = #fp) as T1(N)
cross apply T1.N.nodes('Items/Item') as T2(N)
cross apply T2.N.nodes('Objects/Object') as T3(N)
You have to be the judge which query is the fastest for you.
I just want to add, in case anybody else runs across this, that adding the following option makes a huge difference.
OPTION (OPTIMIZE FOR (#testXml = NULL))
If you'd like to test this yourself, here is a short test script I was running. Just look at the estimated subtree cost between these.
declare #testXml xml set #testXml = '<filters><filter name="test name" type="GREATERTHAN">1</filter><filter name="CLAIMID" type="GREATERTHAN">1</filter></filters>'
select x.value('#name','nvarchar(100) ') filtername,
x.value('.','nvarchar(200)')filtervalue,
x.value('#type','nvarchar(50) ') filtertype
from #testXml.nodes('/filters/filter') as ref(x)
--vs...
select x.value('#name','nvarchar(100) ') filtername,
x.value('.','nvarchar(200)')filtervalue,
x.value('#type','nvarchar(50) ') filtertype
from #testXml.nodes('/filters/filter') as ref(x)
OPTION (OPTIMIZE FOR (#testXml = NULL))
Try this,
We will create a temp table variable for store this xml values & insert to corresponding table Objects
//..Xml value to temp variable
Declare #x xml ='<Items><Item><guid>FC550573-7171-997F-752D-8D65590CBFD6</guid><Objects><Object>
<type>0</type><guid>E10D9DA9-2C8D-8024-2F07-DF21395811BF</guid></Object><Object>
<type>0</type><guid>D8338400-35C7-781E-A039-C0FDDF80714A</guid></Object></Objects>
</Item></Items>';
Declare #Temp_Tbl table (RowId int identity, item_guid nvarchar(36), [type] int, [guid] nvarchar(36));
Insert into #Temp_Tbl SELECT #x.value('(/Items/Item/guid)[1]', 'nvarchar(36)'),
Cont.value('(type)[1]', 'int'), Cont.value('(guid)[1]', 'nvarchar(36)')
FROM #x.nodes('/Items/Item/Objects/Object') AS Obj(Cont);
INSERT INTO [dbo].[Objects] Select item_guid,[type],[guid] from #Temp_Tbl;

Concatenate multiple xml columntype rows in SQL

I have an online form, whereby each entry adds the data as xml to an xml column in SQL.
ApplicationID(uniqueidentifier) | DateModified | ApplicationForm(XML)
What I need to do is perform a select query that will grab all the ApplicationForm xml values, and concatenate them together to form one result, e.g.
Row1: <ApplicationForm type=""></ApplicationForm>
Row2: <ApplicationForm type=""></ApplicationForm>
Select result:
<Applications>
<ApplicationForm type=""></ApplicationForm>
<ApplicationForm type=""></ApplicationForm>
</Applications>
Probably a better way to do it than this, but I specified the ApplicationForm tag as a tag to be removed, and then stripped it out.
DECLARE #a TABLE (ID UNIQUEIDENTIFIER,
DateModified DATETIME,
ApplicationForm XML)
INSERT INTO #a
( ID, DateModified, ApplicationForm )
VALUES ( NEWID(), -- ID - uniqueidentifier
'2010-12-07 18:47:36', -- DateModified - datetime
'<Application><Form>123</Form></Application>'
) ,
( NEWID(), -- ID - uniqueidentifier
'2010-12-07 18:47:36', -- DateModified - datetime
'<Application><Form>456</Form></Application>'
)
DECLARE #Result VARCHAR(MAX)
SET #Result = CONVERT(VARCHAR(MAX), ( SELECT ApplicationForm AS "StripTagOut"
FROM #a
FOR XML PATH(''), ROOT('Applications'), TYPE ))
SELECT CONVERT(xml, REPLACE(REPLACE(#Result, '</StripTagOut>', ''), '<StripTagOut>', ''))
This was an experiment in using XML EXPLICIT which I believe works:
SELECT 1 AS Tag,
NULL AS Parent,
NULL [Applications!1],
NULL [ApplicationForm!2!!XMLTEXT]
UNION ALL
SELECT 2 AS Tag,
1 AS Parent,
NULL [Applications!1],
ApplicationForm [ApplicationForm!2!!XMLTEXT]
FROM YourTable
FOR XML EXPLICIT
For my own gratification, here is the sample script I used
CREATE TABLE XmlTest
(
ApplicationForm xml
)
INSERT INTO XmlTest VALUES ('<ApplicationForm type="a"><SomeTag>SomeContent</SomeTag></ApplicationForm>')
INSERT INTO XmlTest VALUES ('<ApplicationForm type="b"><SomeTag>SomeOtherContent</SomeTag></ApplicationForm>')
SELECT 1 AS Tag,
NULL AS Parent,
NULL [Applications!1],
NULL [ApplicationForm!2!!XMLTEXT]
UNION ALL
SELECT 2 AS Tag,
1 AS Parent,
NULL [Applications!1],
ApplicationForm [ApplicationForm!2!!XMLTEXT]
FROM XmlTest
FOR XML EXPLICIT
Which output
<Applications>
<ApplicationForm type="a">
<SomeTag>SomeContent</SomeTag>
</ApplicationForm>
<ApplicationForm type="b">
<SomeTag>SomeOtherContent</SomeTag>
</ApplicationForm>
</Applications>
Take a look at this page, which lists quite a number of ways to concatenate rows of data.

MS SQL 2005 Table to XML

I have a simple table in SQL Server 2005, I wish to convert this to XML (using the "FOR XML" clause). I'm having trouble getting my XML to look like the required output.
I've tried looking through various tutorials on the web, but I am struggling. Can someone help?
The table I have looks like this
TYPE,GROUP,VALUE
Books,Hardback,56
Books,Softcover,34
CDs,Singles,45
CDS,Multis,78
The output style I need is:
<data>
<variable name="TYPE">
<row>
<column>GROUP</column>
<column>VALUE</column>
</row>
<row>
<column>GROUP</column>
<column>VALUE</column>
</row>
</variable>
<variable name="TYPE">
<row>
<column>GROUP</column>
<column>VALUE</column>
</row>
<row>
<column>GROUP</column>
<column>VALUE</column>
</row>
</variable>
</data>
Edit:
As far as I can tell I require the multiple values. I'm generating XML for use with Xcelsius (Linking XML and Xcelsius) so have no control over in the formatting of the XML. I can generate the XML using ASP as per the linked tutorial, but I was hoping to get it straight from SQL Server.
Edit 2:
I was hoping for something elegant and tidy... but Godeke's example got the closest. Some fiddling with the SQL and I've come up with:
select
"type" as '#name',
"group" as 'row/column',
null as 'row/tmp',
"value" as 'row/column'
from tableName
for xml path('variable'), root('data')
Outputs almost in the exact way I wanted. The null/tmp line doesn't even output; it is just preventing the concatenation. Still the tag <variable name="TYPE"> repeats for each row, which I can't have.
As close as I can get is this:
select "type" as '#name', "group" as 'row/column1', "value" as 'row/column2'
from tableName
for xml path('variable'), root('data')
Naming two items the same ("column" and "column") isn't something I know how to do in one pass, but on the other hand it is an odd XML schema choice; normally elements have unique names if they contain distinct data. The obvious choice (name them both 'row/column') simply concatenates them in the output into one value.
Also note that each returned row will be a "variable" element distinct from the others. To get the nesting without redundant records will require a subquery:
select distinct "type" as '#name'
from Agent
for xml path('variable'), root('data')
was my first thought, but the distinct prevents nesting.
All this makes me think that to get the exact output you need you might have to use EXPLICIT mode. Perhaps my problem is for something like this I punt and use a DOMDocument in code :).
I prefer using for XML PATH, it provides a nicer way to control your elements etc.
See
But this is quite tricky
/*
create table #tablename
(
[type] varchar(20),
[group] varchar(20),
[value] varchar(20)
)
insert into #tablename select 'type1','group11','value111'
insert into #tablename select 'type1','group11','value112'
insert into #tablename select 'type1','group12','value121'
insert into #tablename select 'type1','group12','value122'
insert into #tablename select 'type2','group21','value211'
insert into #tablename select 'type2','group21','value212'
insert into #tablename select 'type2','group22','value221'
insert into #tablename select 'type2','group22','value222'
alter table #tablename add id uniqueidentifier
update #tablename set id = newid()
*/
select [type] as '#name',
(select
(select [column] from
(
select [group] as 'column', tbn1.type, tbn2.[group]
from #tablename tbn3 WHERE tbn3.type = tbn1.type and tbn2.[group] = tbn3.[group]
union
select [value], tbn1.type, tbn2.[group]
from #tablename tbn3 WHERE tbn3.type = tbn1.type and tbn2.[group] = tbn3.[group]
) as s
for xml path(''),type
)
from #tablename tbn2
where tbn2.type = tbn1.type
for xml path('row3'), type
)
from #tableName tbn1
GROUP BY [type]
for xml path('variable'), root('data')
gives you what you are asking for I, but elegant and tidy it is not.
The script below produces the desired format
<DATA>
<VARIABLE TYPE="Books">
<row TYPE="Books">
<GROUP>Hardback</GROUP>
<VALUE>56</VALUE>
</row>
<row TYPE="Books">
<GROUP>Softcover</GROUP>
<VALUE>34</VALUE>
</row>
</VARIABLE>
<VARIABLE TYPE="CDs">
<row TYPE="CDs">
<GROUP>Singles</GROUP>
<VALUE>45</VALUE>
</row>
<row TYPE="CDS">
<GROUP>Multis</GROUP>
<VALUE>78</VALUE>
</row>
</VARIABLE>
</DATA>
Invoke
DECLARE #tblItems table (
[TYPE] varchar(50)
,[GROUP] varchar(50)
,[VALUE] int
)
DECLARE #tblShredded table (
[TYPE] varchar(50)
,[XmlItem] xml
)
DECLARE #xmlGroupValueTuples xml
insert into #tblItems([TYPE],[GROUP],[VALUE]) values( 'Books','Hardback',56)
insert into #tblItems([TYPE],[GROUP],[VALUE]) values( 'Books','Softcover',34)
insert into #tblItems([TYPE],[GROUP],[VALUE]) values( 'CDs','Singles',45)
insert into #tblItems([TYPE],[GROUP],[VALUE]) values( 'CDS','Multis',78)
SET #xmlGroupValueTuples =
(
SELECT
"#TYPE" = [TYPE]
,[GROUP]
,[VALUE]
FROM #tblItems
FOR XML PATH('row'), root('Root')
)
INSERT #tblShredded([TYPE], XmlItem)
SELECT
[TYPE] = XmlItem.value('./row[1]/#TYPE', 'varchar(50)')
,XmlItem
FROM dbo.tvfShredGetOneColumnedTableOfXmlItems(#xmlGroupValueTuples)
SELECT
(
SELECT
VARIABLE =
(
SELECT
"#TYPE" = t.[TYPE]
,(
SELECT
tInner.XmlItem.query('./child::*')
FROM #tblShredded tInner
WHERE tInner.[TYPE] = t.[TYPE]
FOR XML PATH(''), ELEMENTS, type
)
FOR XML PATH('VARIABLE'),type
)
)
FROM #tblShredded t
GROUP BY
t.[TYPE]
FOR XML PATH(''), ROOT('DATA')
where
-- Example Inputs
/*
DECLARE #xmlListFormat xml
SET #xmlListFormat =
'
<XmlListRoot>
<Item>004421UB7</Item>
<Item>59020UH24</Item>
<Item>542514NA8</Item>
</XmlListRoot>
'
*/
-- =============================================
-- Author: 6eorge Jetson
-- Create date: 01/22/3003
-- Description: Shreds an input XML list conforming to the expected list schema
-- =============================================
CREATE FUNCTION [dbo].[tvfShredGetOneColumnedTableOfXmlItems] (#xmlListFormat xml)
RETURNS
#tblResults TABLE (XmlItem xml)
AS
BEGIN
INSERT #tblResults
SELECT
tblShredded.colXmlItem.query('.') as XmlItem
FROM
#xmlListFormat.nodes('/child::*/child::*') as tblShredded(colXmlItem)
RETURN
END