need help regarding querying xml in sql server - sql

i have two table in sql server 2005. in one table table1 there is one column whose data type is xml where we save data in xml format. now i have another table table2 where we store few fileds name. so now i want to write query in such a on xml data which will return those fields value which are defined in table2. how to achieve it with simple sql statement instead of store procedure.
my xml structure and data like below one
<Record xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<DELETED>
<JID>41185</JID>
<WID>0</WID>
<AccountReference>LH169</AccountReference>
<OEReference>Ari002</OEReference>
<InvoiceNumber>0</InvoiceNumber>
<OrderPlacedBy>Mark Catterall</OrderPlacedBy>
<Specialist>0FFICINA MOTTAUTO</Specialist>
<Priority>2</Priority>
<JobType>OUR</JobType>
<JobState>NOTSTARTED</JobState>
<JobAddedDate>2011-05-31T16:17:00</JobAddedDate>
<JobStartedDate>2011-05-31T16:18:00</JobStartedDate>
<JobFinishedDate>1777-01-01T00:00:01</JobFinishedDate>
<JobShippedDate>1777-01-01T00:00:01</JobShippedDate>
<RecievedDate>1777-01-01T00:00:01</RecievedDate>
<UPSShippingNumber />
<CustomerName>02 IRELAND</CustomerName>
<ContactName>ALAN CONLAN</ContactName>
<Telephone>00353868377926</Telephone>
<StandardHours>3.00</StandardHours>
<JobDescription>test for search 2</JobDescription>
<UserName xsi:nil="true" />
<AwaitingCustomer>0</AwaitingCustomer>
<ReturnToCore>0</ReturnToCore>
<AwaitingFromSalvage>0</AwaitingFromSalvage>
<PartDescription>test for search 2</PartDescription>
<PostalCode>IRELAND</PostalCode>
<OURPrice xsi:nil="true" />
<ExchangePrice xsi:nil="true" />
<NewPrice xsi:nil="true" />
<eBayPrice xsi:nil="true" />
<Status>UPDATED</Status>
</DELETED>
</Record>
suppose in my table2 few fields are stored like
JID,WID,AccountReference,OEReference,InvoiceNumber.
so please guide me how to write sql on xml data which will return only JID,WID,AccountReference,OEReference,InvoiceNumber from xml data but filed name will not be hard coded rather it will be fetch from another table table2.
please guide me.

To read data from xml you can use like this:
Select
MyXmlColumn.value('(Record/DELETED/JID)[1]', 'int' ) as JID,
MyXmlColumn.value('(Record/DELETED/WID)[1]', 'int' ) as WID,
MyXmlColumn.value('(Record/DELETED/AccountReference)[1]', 'nvarchar(255)' ) as AccountReference from table2
[update]
create a stored procedure with your parameters:
create procedure getmyxmldata
(
#param1 varchar(50),
#param2 varchar(50)
)
as
begin
declare #myQuery varchar(1000);
set #myQuery = 'Select
MyXmlColumn.value(''(Record/DELETED/' + #param1 + ')[1]'', ''nvarchar(255)'' ) as ' + #param1 + ',
MyXmlColumn.value(''(Record/DELETED/' + #param1 + ')[1]'', ''nvarchar(255)'' ) as ' + #param1 + ' from table2';
EXEC sp_executesql #myQuery
end
It is also possible to read the specified fields from the other table in this stored procedure and create your select statement dynamically without passing parameters.
[Update 2]
you can try this for multiple deleted tags:
Select
Row.value('(./JID)[1]', 'int' ) as JID,
Row.value('(./WID)[1]', 'int' ) as WID,
Row.value('(./AccountReference)[1]', 'nvarchar(255)' ) as AccountReference
from table2
CROSS APPLY MyXmlColumn.nodes('/Record/DELETED') as Record(Row)

Related

Creating a query from an XML input parameter in a stored procedure and verifying the output

I have created a stored procedure that reads XML data as its input. I am having two issues that I am hoping someone can help with.
Issue 1: When I execute the stored procedure, I only get back the first value for AccountType (9). I am expecting/wanting to get back all values for AccountType.
Issue 2: Once I have fixed the above issue I would like to use values from AccountType to select users from another table e.g. dbo.UserData
What I have tried:
I saw this on another SO post that you can debug but I am not sure exactly how to use this or what it's doing.
select col.query('.') as Debug
XML:
<root>
<From>4</From>
<AccountType>9</AccountType>
<AccountType>5</AccountType>
<AccountType>6</AccountType>
<AccountType>7</AccountType>
<AccountType>5</AccountType>
<AccountType>4</AccountType>
<AccountType>1</AccountType>
<AccountType>15</AccountType>
<AccountType>16</AccountType>
<AccountType>1</AccountType>
<AccountType>ivs</AccountType>
<AccountType>10</AccountType>
<AccountType>12</AccountType>
<AccountType>11</AccountType>
<AccountType>tfs</AccountType>
<AccountType>vsa</AccountType>
<AccountType>13</AccountType>
<AccountType>14</AccountType>
<GroupID>1</GroupID>
<GroupID>5</GroupID>
</root>
Stored procedure:
CREATE PROCEDURE dbo.UserSelect
#XMLInput XML
AS
BEGIN
SET NOCOUNT ON;
SELECT DISTINCT
'AccountType' = x.v('AccountType[1]', 'nvarchar(2)')
FROM
#XMLInput.nodes('/root') AS x(v)
END
Execution of stored procedure:
DECLARE #XML as XML
SET #XML = '<root>
<From>4</From>
<AccountType>9</AccountType>
<AccountType>5</AccountType>
<AccountType>6</AccountType>
<AccountType>7</AccountType>
<AccountType>5</AccountType>
<AccountType>4</AccountType>
<AccountType>1</AccountType>
<AccountType>15</AccountType>
<AccountType>16</AccountType>
<AccountType>1</AccountType>
<AccountType>ivs</AccountType>
<AccountType>10</AccountType>
<AccountType>12</AccountType>
<AccountType>11</AccountType>
<AccountType>tfs</AccountType>
<AccountType>vsa</AccountType>
<AccountType>13</AccountType>
<AccountType>14</AccountType>
<GroupID>1</GroupID>
<GroupID>5</GroupID>
</root>'
EXEC dbo.UserSelect #XML
You were close, but you needed to specify the 'AccountType' node in the nodes function. And then use the value function to get the value.
select distinct x.v.[value]('.','nvarchar(2)') AccountType
from #XML.nodes('/root/AccountType') x(v)
In an ITVF (Inline Table Valued Function) it looks like:
create function dbo.GetAccountTypeFromXML
(
#Xml xml
)
returns table
return
select distinct x.v.[value]('.','nvarchar(2)') AccountType
from #XML.nodes('/root/AccountType') x(v)
Which can then be used as, for example:
select *
from dbo.UserData
where AccountType in (select AccountType from dbo.GetAccountTypeFromXML(#Xml))

Convert xml text in a cell to Columns

Our front end development team saves surveys in a SQL database table as xml text. Each survey has different set of fields and need help on how to automatically convert the cell holding the xml text to multiple columns.
Below is an example of the xml text in a cell which needs to be split into individual columns.
<?xml version="1.0" encoding="utf-16"?>
<root>
<userid>JS 30/08/1981</userid>
<column___1>0</column___1>
<column___2>1</column___2>
<column___3>0</column___3>
<column___4>0</column___4>
<column___5>0</column___5>
<column___6>0</column___6>
<column___7>0</column___7>
<column___8>0</column___8>
<column___9>0</column___9>
<column___1_0>0</column___1_0>
<column___1_1>0</column___1_1>
<column___1_2>0</column___1_2>
<column___1_3>0</column___1_3>
<column___1_4>0</column___1_4>
<column___1_5>0</column___1_5>
<column___1_6>0</column___1_6>
<column___1_7>0</column___1_7>
<column___1_8>0</column___1_8>
<column___1_9>0</column___1_9>
<column___2_0>0</column___2_0>
<column___2_1>0</column___2_1>
<column___D_S>0</column___D_S>
<column___A_S>2</column___A_S>
<column___S_S>0</column___S_S>
<userid___u_i_d>5</userid___u_i_d>
</root>
I created a test table using the syntax below:
CREATE TABLE [dbo].[XmlTest](
[id] [int] IDENTITY(1,1) NOT NULL,
[surveyxml] [xml] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
I then loaded 2 records into the test table(the 1st being the XML you have in your example).
Use a query like below:
SELECT
fields.value('(userid/text())[1]', 'varchar(50)') as userid,
fields.value('(column___1/text())[1]', 'varchar(50)') as column1,
fields.value('(column___2/text())[1]', 'varchar(50)') as column2,
fields.value('(column___3/text())[1]', 'varchar(50)') as column3
FROM
xmltest CROSS APPLY
surveyxml.nodes('/root') AS Root(fields)
The following results are returned:
You can add all the fields you want to the query, and change the data type if you know what it is. Good Luck
You can make this as generic dynamic code like this:
drop table if exists #tmp
DECLARE #XML as xml
SET #XML = N'<?xml version="1.0" encoding="utf-16"?>
<root>
<userid>JS 30/08/1981</userid>
<column___1>0</column___1>
<column___2>1</column___2>
<column___3>0</column___3>
<column___4>0</column___4>
<column___5>0</column___5>
<column___6>0</column___6>
<column___7>0</column___7>
<column___8>0</column___8>
<column___9>0</column___9>
<column___1_0>0</column___1_0>
<column___1_1>0</column___1_1>
<column___1_2>0</column___1_2>
<column___1_3>0</column___1_3>
<column___1_4>0</column___1_4>
<column___1_5>0</column___1_5>
<column___1_6>0</column___1_6>
<column___1_7>0</column___1_7>
<column___1_8>0</column___1_8>
<column___1_9>0</column___1_9>
<column___2_0>0</column___2_0>
<column___2_1>0</column___2_1>
<column___D_S>0</column___D_S>
<column___A_S>2</column___A_S>
<column___S_S>0</column___S_S>
<userid___u_i_d>5</userid___u_i_d>
</root>
'
/* First find all the column names and values */
SELECT
b.value('local-name(.)','VARCHAR(50)') AS ColumnName,
b.value('.','VARCHAR(MAX)') AS ColumnValue
into #tmp
FROM #xml.nodes('/root') x(x)
CROSS APPLY x.nodes('*') a(b)
/* Now build the select */
declare #sql nvarchar(max)=''
select #sql=#sql+'
'+iif(#sql='','',',')+''''+ ColumnValue + '''['+ColumnName+']'
from #tmp
set #sql='select '+#sql
exec sp_executesql #sql

How to insert an attribute into xml data which is saved as nvarchar(max)

Let's say there is the following XML data and I want to add an attribute into salary like currency="INR":
<employee>
<salary amount="6000"/>
</employee>
If this data is stored in a column of type XML, then another attribute is being added easily just by using this code snippet:
UPDATE TABLENAME
SET COLUMNNAME.modify('insert attribute currency{"INR"} into (/employee/salary)[1]')
and if this data is stored in a column of type nvarchar(max), then the following query is not working even after casting the data as xml:
UPDATE TABLENAME
SET CAST(CAST(COLUMNNAME AS VARCHAR(MAX)) AS XML).modify('insert attribute currency{"INR"} into (/employee/salary)[1]')
So, help me to resolve second point as I have a column as nvarchar and I need to insert an attribute into saved xml data.
modify() Method works only with variable/column directly and can only used in the SET clause.
So, to solve this since you are storing your data as NVARCHAR, you have two choices:
Alter your table and add a new column with XML datatype, move the data to it from your column, and then UPDATE the data using modify()
Create/declare a table to store your data as XML and do the UPDATE.
Here is an example for what you provide:
CREATE TABLE T
(
Value NVARCHAR(MAX)
);
INSERT INTO T
SELECT N'<employee>
<salary amount="6000"/>
</employee>';
DECLARE #V XML;
SELECT #V = CAST(Value AS XML)
FROM T;
SET #V.modify('insert attribute currency{"INR"} into (/employee/salary)[1]');
UPDATE T
SET Value = CAST(#V AS NVARCHAR(MAX));
SELECT * FROM T;
Live demo

SQL Server 2012 create list of VARBINARY in single XML element

I am currently struggling to find a solution to the following problem.
I have a result set of VARBINARY values - for example:
QAAAAAAAAAE=
QAAAAAAAAAQ=
these results Need to be packed into a XML Element delimited by a single space (to siginify an array of values). Example of how the result should look:
<results>QAAAAAAAAAE= QAAAAAAAAAQ=</results>
The issue I am having while using XML PATH is that I cannot combine a ' ' (varchar) and the result varbinary field. If I add the ' ' before the result and then convert to varbinary the result is incorrect due to having converted the space as well. Here is an example of what I have attempted thus far:
(
STUFF((SELECT DISTINCT ' ' + CONVERT( VARBINARY, id)
FROM results
FOR XML PATH('ns2:children')
),1,1,'')
),
You should not deal with XML on string level. This might have various side effects...
You can try this:
I fill a table with some values in a VARBINARY column:
DECLARE #table TABLE(SomeData VARBINARY(MAX));
INSERT INTO #table VALUES(0x12AF)
,(CAST('test' AS VARBINARY(MAX)))
,(CAST(GETDATE() AS VARBINARY(MAX)));
SELECT *
FROM #table;
The result
SomeData
0x12AF
0x74657374
0x0000A81100AD9F69
If you get this as XML, the conversion to base64 is done implicitly
SELECT * FROM #table FOR XML PATH('result')
the result
<result>
<SomeData>Eq8=</SomeData>
</result>
<result>
<SomeData>dGVzdA==</SomeData>
</result>
<result>
<SomeData>AACoEQCtn2k=</SomeData>
</result>
Now there is XQuery-function data() to your rescue. It will automatically concatenate all sub-values separated by a blank:
SELECT(
SELECT *
FROM #table
FOR XML PATH('result'),TYPE
).query('data(/result/SomeData)') AS result
FOR XML PATH('results')
The result is
<results>
<result>Eq8= dGVzdA== AACoEQCtn2k=</result>
</results>
Pls. try short of SQL Command which could help u to achieve the above result :
SELECT REPLACE(T.Data, '</results><results>', ' ')
FROM
(
SELECT STUFF(
(
SELECT DATA [results]
FROM <table_name> FOR XML PATH('')
), 1, 1, '<') [Data]
) T;
Result :
<results>QAAAAAAAAAE= QAAAAAAAAAQ=</results>
If I understand what do you want?! A way to get <results>QAAAAAAAAAE= QAAAAAAAAAQ=</results> as result is:
select ltrim((
select ' '+cast(id as varchar(50))
from t
group by id
for xml path(''))) results
for xml path('');
SQL Fiddle Demo

auto generate XML using SQL- How to get a outer tag around a group of similar items without using root()?

Ideally, I would like a XML file that looks something like below, however so far my query does not generate the tag for OrderRequests, but only OrderRequest. Below is the query I have used and the XML that needs to be generated.
Query:
declare #xml XML;
declare #RequestFileHeader table
(
ClientCode varchar(10),
CreateTime varchar(40),
BatchNumber int
);
insert into #RequestFileHeader values('CMG','2013-09-16T00:20:13.7306775-07:00',
CAST(RAND() * 1000000 AS INT) )
select RequestFileHeader.*,
OrderRequest.TransactionTime,
(OrderRequest.ReferenceNumber -1000000+ CAST(RAND() *1000000 AS INT))
ReferenceNumber,
'False' as IsRush, ShippingAddress.*
from
#RequestFileHeader RequestFileHeader,
RbcRequest OrderRequest,
RbcOrderShippingAddress ShippingAddress-- , RbcRequest OrderRequests
where (ShippingAddress.RequestId = OrderRequest.RequestId)
for xml AUTO , root('TransactionRequest'), Elements
GO
XML:
<OrderRequests>
<OrderRequest>
<ReferenceNumber>647433081</ReferenceNumber>
<TransactionTime>2014-04-07T04:35:00</TransactionTime>
<IsRush>false</IsRush>
<ShippingAddress>
<Name>ROGER RAI</Name>
<Address1>18855 54A AVE</Address1>
<Address2 />
<Address3 />
<City>SURREY</City>
<Province>BC</Province>
<PostalCode>V3S6R4</PostalCode>
<HomePhone>6046008564</HomePhone>
<BusinessPhone>6047247883</BusinessPhone>
</ShippingAddress>
<ProgramType>AV</ProgramType>
<Comments />
<Items>
<Item>
<Sku>CC03327-SLV</Sku>
<ProductCode>AA1346</ProductCode>
<Quantity>1</Quantity>
</Item>
</Items>
</OrderRequest>
Embed the query you already have in a query that creates the root node. You also need to add the type directive to your existing query.
select (
-- Replace this with your existing query.
select *
from T
for xml auto, root('OrderRequest'), elements, type
)
for xml path('OrderRequests')