how to manage XML FILE WITH SPACE - sql-server

I have the following xml,
I try to get data to MSSQL server table with OPENROWSET
and I can't get the product id value,
there is some different way to get the product id?
thanks,
XML Content:
<?xml version="1.0" encoding="UTF-8"?>
<manufacturer url="https://www.manufacturer.gr" name="https://www.manufacturer.gr" encoding="utf-8"><created_at>2021-12-08</created_at>
<products>
<product id="12289">
<name><![CDATA[ΠΑΡΑΜΥΘΙΑ ΜΕ ΖΩΑΚΙΑ]]></name>
<link>https://www.manufacturer.gr/el/paramythia-me-zwakia.html</link>
<image>
<image1>https://assets.manufacturer.gr/media/catalog/product/9/7/9789604969647_1.png</image1>
<image2>https://assets.manufacturer.gr/media/catalog/product/9/7/9789604969647_bc_1.png</image2>
<image3>https://assets.manufacturer.gr/media/catalog/product/9/7/9789604969647_3D_1.png</image3>
</image>
<category>
<![CDATA[category]]>
</category>
<series>
<![CDATA[Εικο]]></series>
<series_id>123</series_id>
<author>
<![CDATA[]]></author><author_id/><age><![CDATA[3-4]]></age><description><![CDATA[description]]></description>
<price>12.20</price><isbn>978-960-496-964-7</isbn>
<pages>122</pages>
<dimensions>22 x 28.2</dimensions>
<weight>0.8420</weight>
<instock>Y</instock>
<availability>Μη διαθέσιμο</availability>
<barcode>9789604969647</barcode>
<manufacturer><![CDATA[]]></manufacturer>
<fixed_price>ΕΚΤΟΣ ΕΝΙΑΙΑΣ ΤΙΜΗΣ</fixed_price>
</product>
</products>
</manufacturer>
SQL Code
DECLARE #input XML
SET #input = (SELECT * FROM OPENROWSET(BULK 'C:\content.xml', single_blob) AS b)
SELECT
cast(doc.col.query('id[1]')as nvarchar(100)) as id,
doc.col.value('name[1]', 'nvarchar(100)') AS title,
doc.col.value('description[1]', 'nvarchar(max)') AS description,
doc.col.value('age[1]', 'nvarchar(100)') AS age,
doc.col.value('category[1]', 'nvarchar(500)') AS category,
doc.col.value('price[1]', 'nvarchar(100)') AS price,
doc.col.value('tax[1]', 'float') AS tax,
doc.col.value('availability[1]', 'nvarchar(100)') AS availability,
doc.col.value('manufacturer[1]', 'nvarchar(100)') AS manufacturer,
doc.col.value('isbn[1]', 'nvarchar(100)') AS mpn,
doc.col.value('barcode[1]', 'nvarchar(100)') AS ean,
doc.col.value('weight[1]', 'nvarchar(100)') AS weight,
doc.col.value('fixed_price[1]', 'nvarchar(100)') AS fixed_price
FROM #input.nodes('manufacturer/products/product') doc(col)

Related

Query from XML Column

This results are located in XML column of the table.
<?xml version="1.0" encoding="UTF-8"?>
<client id_issue="5488">
<surname value="Hasanov"/>
<name value="Mehman"/>
<middle_name value="Adil"/>
<date_birth value="1986-05-19"/>
</client>
I want to query the values of the surname,name,middle_name and date_birth from XML column.
Like below:
surname name middle_name date_birth`
----------------------------------------------
Hasanov Mehman Adil 1986-05-19
You could use:
SELECT s.c.value('#id_issue', 'INT') AS id_issue
,s.c.value('surname[1]/#value', 'NVARCHAR(100)') AS surname
,s.c.value('name[1]/#value', 'NVARCHAR(100)') AS name
,s.c.value('middle_name[1]/#value', 'NVARCHAR(100)') AS middle_name
,s.c.value('date_birth[1]/#value', 'DATE') AS dob
FROM tab
CROSS APPLY tab.col.nodes('/client') s(c);
db<>fiddle demo
EDIT:
I have Got the error...Msg 9506, Level 16, State 1, Line 1 The XMLDT method 'nodes' can only be invoked on columns of type xml. my xml column type is ntext
NTEXT is deprecated. You could cast NTEXT to XML and then parse it.
SELECT s.c.value('#id_issue', 'INT') AS id_issue
,s.c.value('surname[1]/#value', 'NVARCHAR(100)') AS surname
,s.c.value('name[1]/#value', 'NVARCHAR(100)') AS name
,s.c.value('middle_name[1]/#value', 'NVARCHAR(100)') AS middle_name
,s.c.value('date_birth[1]/#value', 'DATE') AS dob
FROM tab
CROSS APPLY (SELECT TRY_CAST(REPLACE(CAST(tab.col AS NVARCHAR(MAX)),'<?xml version="1.0" encoding="UTF-8"?>','') AS XML)) sub(col)
CROSS APPLY sub.col.nodes('/client') s(c)
db<>fiddle demo
You can use XQuery as follows:
DECLARE #q XML= '<?xml version="1.0" encoding="UTF-8"?>
<client id_issue="5488">
<surname value="Hasanov"/>
<name value="Mehman"/>
<middle_name value="Adil"/>
<date_birth value="1986-05-19"/>
</client>';
SELECT #q.value('(client/surname/#value)[1]', 'varchar(max)') AS surname,
#q.value('(client/name/#value)[1]', 'varchar(max)') AS name,
#q.value('(client/middle_name/#value)[1]', 'varchar(max)') AS middle_name,
#q.value('(client/date_birth/#value)[1]', 'date') AS date_birth;
Read more about XQuery: https://learn.microsoft.com/en-us/sql/xquery/xquery-language-reference-sql-server?view=sql-server-2017
If you have a table and you are going to parse the xml inside the table you can try this, which is similar to above mentioned solution:
Suppose that you have a table like this:
CREATE TABLE tblTest
(
id INT PRIMARY KEY,
msg XML
);
and you have inserted some data like this into that table:
INSERT INTO tblTest
VALUES
(1,
'<?xml version="1.0" encoding="UTF-8"?>
<client id_issue="5488">
<surname value="Hasanov"/>
<name value="Mehman"/>
<middle_name value="Adil"/>
<date_birth value="1986-05-19"/>
</client>'),
(2,
'<?xml version="1.0" encoding="UTF-8"?>
<client id_issue="5488">
<surname value="Alimov"/>
<name value="Ghader"/>
<middle_name value="Ragman"/>
<date_birth value="1950-04-20"/>
</client>');
So you can simply parse it using XQuery as:
SELECT msg.value('(client/surname/#value)[1]', 'varchar(max)') AS surname,
msg.value('(client/name/#value)[1]', 'varchar(max)') AS name,
msg.value('(client/middle_name/#value)[1]', 'varchar(max)') AS middle_name,
msg.value('(client/date_birth/#value)[1]', 'date') AS date_birth
FROM tblTest;
Even if your msg does not have XML data type(for example it would be varchar(max)) then you need to cast it to xml prior to querying using XQuery like this:
SELECT CAST(msg AS XML).value('(client/surname/#value)[1]', 'varchar(max)') AS surname,
CAST(msg AS XML).value('(client/name/#value)[1]', 'varchar(max)') AS name,
CAST(msg AS XML).value('(client/middle_name/#value)[1]', 'varchar(max)') AS middle_name,
CAST(msg AS XML).value('(client/date_birth/#value)[1]', 'date') AS date_birth
FROM tblTest;
Executing the above query, you'll get the following error:
unable to switch the encoding
You can rewrite it as:
SELECT CAST(REPLACE(CAST([msg] AS NVARCHAR(MAX)), 'encoding="utf-8"', '') AS XML).value('(client/surname/#value)[1]', 'nvarchar(max)') AS surname,
CAST(REPLACE(CAST([msg] AS NVARCHAR(MAX)), 'encoding="utf-8"', '') AS XML).value('(client/name/#value)[1]', 'nvarchar(max)') AS [name],
CAST(REPLACE(CAST([msg] AS NVARCHAR(MAX)), 'encoding="utf-8"', '') AS XML).value('(client/middle_name/#value)[1]', 'nvarchar(max)') AS middle_name,
CAST(REPLACE(CAST([msg] AS NVARCHAR(MAX)), 'encoding="utf-8"', '') AS XML).value('(client/date_birth/#value)[1]', 'nvarchar(max)')AS date_birth
FROM tblTest;
And finally if you need to use the output of the aforementioned query in other query(like JOIN to to other relation) you can put it as a subquery and use it.
SELECT K.surname,
K.name,
K.middle_name,
K.date_birth
FROM
(
SELECT msg.value('(client/surname/#value)[1]', 'varchar(max)') AS surname,
msg.value('(client/name/#value)[1]', 'varchar(max)') AS name,
msg.value('(client/middle_name/#value)[1]', 'varchar(max)') AS middle_name,
msg.value('(client/date_birth/#value)[1]', 'date') AS date_birth
FROM tblTest
) AS K INNER JOIN ...
Worked with this query
SELECT
CAST(REPLACE(CAST([msg] AS NVARCHAR(MAX)), 'encoding="utf-8"', '')
AS XML).value('(client/ surname/#value)[1]', 'nvarchar(max)') AS surname,
CAST(REPLACE(CAST([msg] AS NVARCHAR(MAX)), 'encoding="utf-8"', '')
AS XML).value('(client/ name/#value)[1]', 'nvarchar(max)') AS [name],
CAST(REPLACE(CAST([msg] AS NVARCHAR(MAX)), 'encoding="utf-8"', '')
AS XML).value('(client/ middle_name/#value)[1]', 'nvarchar(max)') AS middle_name,
CAST(REPLACE(CAST([msg] AS NVARCHAR(MAX)), 'encoding="utf-8"', '')
AS XML).value('(client/ date_birth/#value)[1]', 'nvarchar(max)') AS date_birth

Select into xml from table in sql server with distinct id

I have table that contains three columns:
[ID],[Name],[Value]
My select for xml result:
DECLARE #xml XML
SET #xml = (
SELECT
ID
,[Name]
,[Value]
FROM [CustomerDetails]
WHERE ID = 1
FOR XML PATH(''), ROOT('Customer')
)
SELECT #xml
My select return xml with multiple ID properties:
<Customer>
<ID>1</ID>
<Name>FirstName</Name>
<Value>firstName</Value>
<ID>1</ID>
<Name>LastName</Name>
<Value>lastName</Value>
<ID>1</ID>
<Name>Age</Name>
<Value>20</Value>
<ID>1</ID>
<Name>City</Name>
<Value>London</Value>
</Customer>
I need next xml:
<Customer>
<ID>1</ID>
<Name>FirstName</Name>
<Value>firstName</Value>
<Name>LastName</Name>
<Value>lastName</Value>
<Name>Age</Name>
<Value>20</Value>
<Name>City</Name>
<Value>London</Value>
</Customer>
How to return this kind of XML?
I have shortened name of columns:
declare #id int = 1
select id, n, v from
(select #id id, null n, null v, 1 as rn from t
union
select null, n, v, 2 as rn from t
where id = #id
) t order by rn
for xml path(''), root('customer')
Output:
<customer><id>1</id><n>n1</n><v>v1</v><n>n2</n><v>v2</v><n>n3</n><v>v3</v></customer>
Fiddle http://sqlfiddle.com/#!3/70ea0/4

Trying to store result in xml format in variable sql server

i am just trying to compare two xml and try to store the difference into another variable called #DiffXML but getting error called Incorrect syntax near the keyword 'SET'.
just guide what to fix. thanks
DECLARE #XML1 XML
DECLARE #XML2 XML
DECLARE #DiffXML nvarchar(max)
SET #DiffXML=''
SET #XML1 =
'<NewDataSet>
<Employee>
<EmpID>1005</EmpID>
<Name> keith </Name>
<DOB>12/02/1981</DOB>
<DeptID>ACC001</DeptID>
<Salary>10,500</Salary>
</Employee>
</NewDataSet>'
SET #XML2 =
'<NewDataSet>
<Employee>
<EmpID>1006</EmpID>
<Name> keith </Name>
<DOB>05/02/1981</DOB>
<DeptID>ACC002</DeptID>
<Salary>10,900</Salary>
</Employee>
</NewDataSet>'
;with XML1 as
(
select T.N.value('local-name(.)', 'nvarchar(100)') as NodeName,
T.N.value('.', 'nvarchar(100)') as Value
from #XML1.nodes('/NewDataSet/Employee/*') as T(N)
),
XML2 as
(
select T.N.value('local-name(.)', 'nvarchar(100)') as NodeName,
T.N.value('.', 'nvarchar(100)') as Value
from #XML2.nodes('/NewDataSet/Employee/*') as T(N)
)
SET #DiffXML=(select * from
(
select coalesce(XML1.NodeName, XML2.NodeName) as FieldName,
XML1.Value as OldValue,
XML2.Value as NewValue
from XML1
full outer join XML2
on XML1.NodeName = XML2.NodeName
where coalesce(XML1.Value, '') <> coalesce(XML2.Value, '')
) x FOR xml AUTO,elements XSINIL)
print #DiffXML
Change that from
SET #DiffXML=(select * from
to
SELECT #DiffXML=(select * from
and you will get your result printed

XML Parsing & T-SQL

Given the following from an XML field in a table:
<View>
<Criminal xmlns="http://tempuri.org/crimes.xsd">
<Person>
<PersonID>1234</PersonID>
<LastName>SMITH</LastName>
<FirstName>KEVIN</FirstName>
<Cases>
<PersonID>1234</PersonID>
<CaseNumber>12CASE34</CaseNumber>
</Cases>
</Person>
</Criminal>
</View>
How would I pull the Person/PersonID, LastName, Firstname info? Same goes for the CaseNumber.
My next issue is similar to above but lets add a second namespace:
<MessageContent xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Content>Content in here!!</Content>
<Type>Empty</Type>
</MessageContent>
Notice I have 2 namespaces in there AND they also have ":xsi" and ":xsd" in there too. I think those are referred to as schemas.
Try this:
DECLARE #table TABLE (ID INT NOT NULL, XmlContent XML)
INSERT INTO #table VALUES(1, '<View>
<Criminal xmlns="http://tempuri.org/crimes.xsd">
<Person>
<PersonID>1234</PersonID>
<LastName>SMITH</LastName>
<FirstName>KEVIN</FirstName>
<Cases>
<PersonID>1234</PersonID>
<CaseNumber>12CASE34</CaseNumber>
</Cases>
</Person>
</Criminal>
</View>')
;WITH XMLNAMESPACES('http://tempuri.org/crimes.xsd' AS ns)
SELECT
PersonID = XmlContent.value('(/View/ns:Criminal/ns:Person/ns:PersonID)[1]', 'int'),
FirstName = XmlContent.value('(/View/ns:Criminal/ns:Person/ns:FirstName)[1]', 'varchar(50)'),
LastName = XmlContent.value('(/View/ns:Criminal/ns:Person/ns:LastName)[1]', 'varchar(50)')
FROM #table
WHERE ID = 1
Returns an output of:
And for your second part of the question: yes, you have two namespaces defined - but they're not being used at all - so you can basically just ignore them:
INSERT INTO #table VALUES(2, '<MessageContent xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Content>Content in here!!</Content>
<Type>Empty</Type>
</MessageContent>')
SELECT
Content = XmlContent.value('(/MessageContent/Content)[1]', 'varchar(50)'),
Type = XmlContent.value('(/MessageContent/Type)[1]', 'varchar(50)')
FROM #table
WHERE ID = 2
Returns:

Import XML with Attribute to SQL Server Table

I can't get the value for the XML attribute 'Country' into my table.
What am I doing wrong?
Here is my XML:
<?xml version="1.0" encoding="utf-8"?>
<CustomerDetails>
<PersonalInfo Country="USA">
<CustID>1001</CustID>
<CustLastName>Smith</CustLastName>
<DOB>2011-05-05T09:25:48.253</DOB>
<Address>
<Addr1>100 Smith St.</Addr1>
<City>New York</City>
</Address>
</PersonalInfo>
</CustomerDetails>
Here is my SQL:
Drop table #Cust
CREATE TABLE #Cust
(CustID INT, CustLastName VARCHAR(10)
, DOB DATETIME, Addr1 VARCHAR(100), City VARCHAR(10), Country VARCHAR(20))
insert into #Cust
select
c3.value('CustID[1]','int'),
c3.value('CustLastName[1]','varchar(10)'),
c3.value('DOB[1]','DATETIME'),
c3.value('(Address/Addr1)[1]','VARCHAR(100)'),
c3.value('(Address/City)[1]','VARCHAR(10)'),
c3.value('Country[1]','VARCHAR(20)')
from
(
select
cast(c1 as xml)
from
OPENROWSET (BULK 'C:\Users\wattronts\Documents\XMLImportTest.xml',SINGLE_BLOB) as T1(c1)
)as T2(c2)
cross apply c2.nodes('/CustomerDetails/PersonalInfo') T3(c3)
Select * from #Cust
Thanks for your help.
Use # to specify that you want an attribute.
T3.c3.value('#Country', 'varchar(50)')

Resources