Why is select query not working? - sql

I am trying to select each PartNum, WarehouseCode, and OnhandQty from the "StkPart" attributes and select the plant from the "Plant" attribute. There is only one "Plant" in this xml file and the "Plant" would be associated with each row from the "StkPart" attribute.
For Example:
PartNum WarehouseCode OnhandQty Plant
1. 10-12345 Corona 150 MfgSys
2. 10-12351 Cork 1 MfgSys
3. 10-51617a Here 198 MfgSys
4. 10-97654 There 67 MfgSys
This is what I have been trying (The XML code is at the bottom):
This code works and enters the data into my table:
USE Database
GO
CREATE TABLE XMLwithOpenXML
(
Id INT IDENTITY PRIMARY KEY,
XMLData XML,
LoadedDateTime DATETIME
)
INSERT INTO XMLwithOpenXML(XMLData, LoadedDateTime)
SELECT CONVERT(XML, BulkColumn) AS BulkColumn, GETDATE()
FROM OPENROWSET(BULK 'C:\Test\StockStatusReport30597.XML', SINGLE_BLOB) AS x;
SELECT * FROM XMLwithOpenXML
Then I try to select the data, but this is not working:
USE Database
GO
DECLARE #XML AS XML, #hDoc AS INT, #SQL NVARCHAR (MAX)
SELECT #XML = XMLData FROM XMLwithOpenXML
EXEC sp_xml_preparedocument #hDoc OUTPUT, #XML
SELECT PartNum
FROM OPENXML(#hDoc, 'ReportDataSet/PartNum')
WITH
(
PartNum [varchar](50) '#PartNum'
)
EXEC sp_xml_removedocument #hDoc
GO
How do I get the above code to work?
Here is the XML file to download:
http://wikisend.com/download/101282/StockStatusReport30597.XML

This might help
Declare #xml xml = N'<ReportDataSet
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
...
</ReportDataSet>'
Select
N.value('PartNum[1]', 'varchar(20)') PartNum,
N.value('WarehouseCode[1]', 'varchar(20)') WarhouseCode,
N.value('OnhandQty[1]', 'int') OnhandQty,
#xml.value('(/ReportDataSet/Plant/Plant)[1]', 'varchar(20)') Plant
from
#xml.nodes('/ReportDataSet/StkPart') as T(n)
I've cut some stuff out of the example below to fit into the limitations of SQLFiddle, but it worked with the query from the question with appropriate namespaces added:
Example SQLFiddle
For your big data example, you'll need to set the default namespace for the query:
With xmlnamespaces (default 'http://www.epicor.com/Mfg/100')
Select
N.value('PartNum[1]', 'varchar(20)') PartNum,
N.value('WarehouseCode[1]', 'varchar(20)') WarhouseCode,
N.value('OnhandQty[1]', 'decimal(10,2)') OnhandQty,
#xml.value('(/ReportDataSet/Plant/Plant)[1]', 'varchar(20)') Plant
from
#xml.nodes('/ReportDataSet/StkPart') as T(n)

Related

How to parse XML file in a folder with dynamic t-sql?

I'd like to change this XML to SQL statement below to work with a path rather than a file name, at the moment it's looking for 'C:\Test\XML\PT38.xml'.
I need it to parse any .XML file in the folder rather than look for a specific one. It will be just one file at a time but they'll have different names (number increase: PT39, PT40, etc.).
I tried adding a variable for the path then changing the BULK to look for the variable, but it failed as expected.
I've read something about creating a temporary table then parse the date, but I'm not sure that would work for me.
I'd appreciate the help.
This is what I tried:
DECLARE #xmlFileName varchar(100) = 'C:\Test\XML\'
FROM OPENROWSET(BULK ''' + #xmlFileName + ''', SINGLE_BLOB) AS T(MY_XML)) AS T(MY_XML)
This is the XML content:
<?xml version="1.0" encoding="UTF-8" ?>
<MOD1>
<DC BEGIN="1">
<DC4 SEGMENT="1">
<TABNAM>DC4</TABNAM>
<DOCNUM>0000003899888135</DOCNUM>
</DC4>
<ZPR SEGMENT="1">
<AUFNR>000915229446</AUFNR>
<LNO>RM01PL01</LNO>
<CHARG>0006186588</CHARG>
<STR2>211609</STR2>
<QTY>4166.000</QTY>
<PLN_ORDER>6963701111</PLN_ORDER>
</ZPR>
</DC>
</MOD1>
This is the SQL table:
CREATE TABLE XMLTESTTABLE
(
PON int,
ASP int,
LTN varchar(11),
GAS int,
QY varchar(15),
LNO varchar(2),
StartTime date,
);
This is the statement:
INSERT INTO XMLTESTTABLE(PON, ASP, LTN, GAS, QY, LNO, StartTime)
SELECT ZPRM.value('(AUFNR/text())[1]', 'int')
, ZPRM.value('(CHARG/text())[1]', 'int')
, ZPRM.value('(PLN_ORDER/text())[1]', 'VARCHAR(10)')
, ZPRM.value('(CHARG/text())[1]', 'int')
, ZPRM.value('(QTY/text())[1]', 'DECIMAL(10,0)') AS [qty]
, RIGHT(ZPRM.value('(LNO/text())[1]', 'VARCHAR(10)'), 2) AS [LNO]
, TRY_CAST(STUFF(STUFF(ZPRM.value('(STR2/text())[1]', 'CHAR(6)'),3,0,':'),6,0,':') AS TIME)
FROM (SELECT TRY_CAST(MY_XML AS xml)
FROM OPENROWSET(BULK 'C:\Test\XML\PT38.xml', SINGLE_BLOB) AS T(MY_XML)) AS T(MY_XML)
CROSS APPLY MY_XML.nodes('/MOD1/DC/ZPR') AS MY_XML(ZPRM);
It is much easier to implement in SQL Server 2017 and later. It has much better API to deal with the file system.
Please try the following solution. It will work in SQL Server 2012.
I modified the StartTime column data type as TIME(0).
You would need to modify #folder variable value to match what you have in your environment.
SQL
USE tempdb;
GO
DROP TABLE IF EXISTS dbo.XMLTESTTABLE;
CREATE TABLE dbo.XMLTESTTABLE
(
PON varchar(10),
ASP int,
LTN varchar(11),
GAS int,
QY varchar(15),
LNO varchar(2),
StartTime TIME(0)
);
DECLARE #xml XML
, #sql NVARCHAR(MAX)
, #XMLfileName VARCHAR(256) -- 'e:\Temp\TradeFeed\PT38.xml';
, #folder VARCHAR(256) = 'e:\Temp\TradeFeed';
DECLARE #tbl TABLE (
id INT IDENTITY(1,1) PRIMARY KEY,
[fileName] VARCHAR(512),
depth INT,
isfile BIT
);
INSERT INTO #tbl ([fileName], depth, isfile)
EXEC master.sys.xp_dirtree #folder,1,1;
-- just to see
SELECT * FROM #tbl;
-- filter out not need files
SELECT TOP(1) #XMLfileName = CONCAT(#folder, '\', [fileName])
FROM #tbl
WHERE isfile = 1
AND [fileName] LIKE '%.xml';
SET #sql = N'SELECT #xmlOut = XmlDoc FROM OPENROWSET (BULK ' + QUOTENAME(#XMLfileName,NCHAR(39)) + ', SINGLE_BLOB) AS Tab(XmlDoc)';
EXEC master.sys.sp_executesql #sql, N'#xmlOut XML OUTPUT', #xmlOut = #xml OUTPUT;
INSERT INTO XMLTESTTABLE(PON, ASP, LTN, GAS, QY, LNO, StartTime)
SELECT #xml.value('(/MOD1/DC/DC4/TABNAM/text())[1]', 'VARCHAR(10)')
, c.value('(CHARG/text())[1]', 'int')
, c.value('(PLN_ORDER/text())[1]', 'VARCHAR(10)')
, c.value('(CHARG/text())[1]', 'int')
, c.value('(QTY/text())[1]', 'DECIMAL(10,0)') AS [qty]
, RIGHT(c.value('(LNO/text())[1]', 'VARCHAR(10)'), 2) AS [LNO]
, TRY_CAST(STUFF(STUFF(c.value('(STR2/text())[1]', 'CHAR(6)'),3,0,':'),6,0,':') AS TIME(0))
FROM #xml.nodes('/MOD1/DC/ZPR') AS t(c);
-- test
SELECT * FROM dbo.XMLTESTTABLE;
Output
+-----------+---------+------------+---------+------+-----+-----------+
| PON | ASP | LTN | GAS | QY | LNO | StartTime |
+-----------+---------+------------+---------+------+-----+-----------+
| DC4 | 6186588 | 6963701111 | 6186588 | 4166 | 01 | 21:16:09 |
+-----------+---------+------------+---------+------+-----+-----------+

Import xml data in SQL Server 2017

I have XML data like this:
<?xml version="1.0" ?>
<SettlementFile>
<Transaction>
<Identifier>
<StationID>049215901 </StationID>
<TransactionTimestamp>2021-04-01T10:39:32</TransactionTimestamp>
</Identifier>
<TerminalInfo>
<TerminalID>21590151</TerminalID>
<TerminalType>2</TerminalType>
</TerminalInfo>
<TransactionInfo>
<TransactionType>0</TransactionType>
<TransactionAmount>3.74</TransactionAmount>
<CurrencyCode>978</CurrencyCode>
<CustomerInput>
<Mileage>0</Mileage>
</CustomerInput>
<TicketNumber>213510037</TicketNumber>
<AuthorisationType>1</AuthorisationType>
</TransactionInfo>
</Transaction>
</SettlementFile>
My SQL Server table structure:
CREATE TABLE dbo.Import_Oase
(
StationID varchar(50) NULL,
TransactionTimestamp datetime NULL,
TicketNumber int NULL,
Mileage varchar(50) NULL
) ON PRIMARY
I'm trying to use this SELECT query:
SELECT
MY_XML.Details.query('StationID') .value('.', 'VARCHAR(50)'),
MY_XML.Details.query('TransactionTimestamp').value('.', 'Datetime'),
MY_XML.Details.query('TicketNumber') .value('.', 'Integer'),
MY_XML.Details.query('Mileage') .value('.', 'VARCHAR(50)')
FROM
(SELECT
CAST(MY_XML AS XML)
FROM
OPENROWSET(BULK '\\EO-TEST\SQL-Daten\Temp\MY_XML.xml', SINGLE_BLOB) AS T(MY_XML)
) AS T(MY_XML)
CROSS APPLY
MY_XML.nodes('SettlementFile/Transaction/Identifier, SettlementFile/Transaction/TransactionInfo, SettlementFile/Transaction/TransactionInfo/CustomerInput') AS MY_XML (Details);
I need to get the result in one line because it is all for 1 transactions. But it is in three different line in SQL.
Please try the following solution.
When you are satisfied with the outcome, just uncomment the INSERT INTO line.
SQL
WITH rs (xmlData) AS
(
SELECT TRY_CAST(BulkColumn AS XML)
FROM OPENROWSET(BULK N'e:\Temp\ daryosmitan.xml', SINGLE_BLOB) AS x
)
-- INSERT INTO dbo.Import_Oase (StationID, TransactionTimestamp, TicketNumber, Mileage)
SELECT c.value('(Identifier/StationID/text())[1]', 'VARCHAR(50)') AS StationID
, c.value('(Identifier/TransactionTimestamp/text())[1]', 'DATETIME') AS TransactionTimestamp
, c.value('(TransactionInfo/TicketNumber/text())[1]', 'VARCHAR(50)') AS TicketNumber
, c.value('(TransactionInfo/CustomerInput/Mileage/text())[1]', 'INT') AS Mileage
FROM rs
CROSS APPLY xmlData.nodes('/SettlementFile/Transaction') AS t(c);

Uniqueidentifier conversion failed when Importing XML file to SQL Server

I'm trying to import data from an XML file into a SQL Server table. However, I'm getting the error:
Conversion failed when converting from a character string to uniqueidentifier
It says it's in state 2 of Line 6 (Id3), but I assume the conversion is failing in other places.
XML:
<ImportExportObject>
<Objects>
<MyObject>
<Id>123e5c8c-a7fc-40da-440e-12348bc612e8</Id>
<Id2>123e5c8c-a7fc-40da-440e-12348bc612e8</Id2>
<Name>en</Name>
<Id3>123e5c8c-a7fc-40da-440e-12348bc612e8</Id3>
</MyObject>
</Objects>
</ImportExportObject>
SQL code:
INSERT INTO MyTable(ID, Id2, Name, Id3)
SELECT
MyXMLDocument.query('Id').value('.', 'uniqueidentifier'),
MyXMLDocument.query('Id2').value('.', 'uniqueidentifier'),
MyXMLDocument.query('Name').value('.', 'NVARCHAR(50)'),
MyXMLDocument.query('Id3').value('.', 'uniqueidentifier'),
FROM (SELECT CAST(MyXMLDocument AS xml)
FROM OPENROWSET(BULK 'C:\Users\myUser\Documents\MyXMLDocument.xml', SINGLE_BLOB) AS T(MyXMLDocument)) AS T(MyXMLDocument)
CROSS APPLY MyXMLDocument.nodes('ImportExportObject/Objects/MyObject') AS MyXMLDocument (MyObject);
How do I resolve this error?
I've been unable to get Select Cast and Convert to work - and .value() requires string literals so '#Id' doesn't seem to work.
Quite unsure here - any help is much appreciated!
How about having MyTable with an automatically imported id and not importing that? Would that work for what you want?
You can the code below to find which values cannot be converted to uniqueidentifier:
SELECT
MyXMLDocument.query('Id').value('.', 'NVARCHAR(50)'),
MyXMLDocument.query('Id2').value('.', 'NVARCHAR(50)'),
MyXMLDocument.query('Id3').value('.', 'NVARCHAR(50)')
FROM (SELECT CAST(MyXMLDocument AS xml)
FROM OPENROWSET(BULK 'C:\Users\myUser\Documents\MyXMLDocument.xml', SINGLE_BLOB) AS T(MyXMLDocument)) AS T(MyXMLDocument)
CROSS APPLY MyXMLDocument.nodes('ImportExportObject/Objects/MyObject') AS MyXMLDocument (MyObject)
WHERE TRY_CAST(MyXMLDocument.query('Id').value('.', 'NVARCHAR(50)') AS uniqueidentifier) IS NULL
OR TRY_CAST(MyXMLDocument.query('Id2').value('.', 'NVARCHAR(50)') AS uniqueidentifier) IS NULL
OR TRY_CAST(MyXMLDocument.query('Id3').value('.', 'NVARCHAR(50)') AS uniqueidentifier) IS NULL
The idea is to use TRY_CAST which will return NULL if the data cannot be converted.
declare #x xml = N'<ImportExportObject>
<Objects>
<MyObject>
<Id>123e5c8c-a7fc-40da-440e-12348bc612e8</Id>
<Id2>123e5c8c-a7fc-40da-440e-12348bc612e8</Id2>
<Name>en</Name>
<Id3>123e5c8c-a7fc-40da-440e-12348bc612e8</Id3>
</MyObject>
</Objects>
</ImportExportObject>';
SELECT
MyXML.MyObject.value('Id[1]', 'uniqueidentifier'),
MyXML.MyObject.value('Id2[1]', 'uniqueidentifier'),
MyXML.MyObject.value('Name[1]', 'NVARCHAR(50)'),
MyXML.MyObject.value('Id3[1]', 'uniqueidentifier')
FROM
(
SELECT #x
-- CAST(MyXMLDocument AS xml) FROM OPENROWSET(BULK 'C:\Users\myUser\Documents\MyXMLDocument.xml', SINGLE_BLOB)
) AS T(MyXMLDocument)
CROSS APPLY MyXMLDocument.nodes('./ImportExportObject/Objects/MyObject') AS MyXML(MyObject);

SQL: How can I get the value of an attribute in XML datatype?

I have the following xml in my database:
<email>
<account language="en" ... />
</email>
I am using something like this now: but still have to find the attribute value.
SELECT convert(xml,m.Body).query('/Email/Account')
FROM Mail
How can I get the value of the language attribute in my select statement with SQL?
Use XQuery:
declare #xml xml =
'<email>
<account language="en" />
</email>'
select #xml.value('(/email/account/#language)[1]', 'nvarchar(max)')
declare #t table (m xml)
insert #t values
('<email><account language="en" /></email>'),
('<email><account language="fr" /></email>')
select m.value('(/email/account/#language)[1]', 'nvarchar(max)')
from #t
Output:
en
fr
This should work:
DECLARE #xml XML
SET #xml = N'<email><account language="en" /></email>'
SELECT T.C.value('#language', 'nvarchar(100)')
FROM #xml.nodes('email/account') T(C)
It depends a lot on how you're querying the document. You can do this, though:
CREATE TABLE #example (
document NText
);
INSERT INTO #example (document)
SELECT N'<email><account language="en" /></email>';
WITH XmlExample AS (
SELECT CONVERT(XML, document) doc
FROM #example
)
SELECT
C.value('#language', 'VarChar(2)') lang
FROM XmlExample CROSS APPLY
XmlExample.doc.nodes('//account') X(C);
DROP TABLE #example;
EDIT after changes to your question.
if the xml data is stored in sql server as a string column then use cast
select cast(your_field as XML)
.value('(/email/account/#language)[1]', 'varchar(20)')
from your_table

How to Generate xml from sql for below pattern

I'm writing one stored procedure, which I have to create a xml column from db.
µ = CHAR(181) this is value separator,
¶ = CHAR(182) this is row separator
This is the statement I wrote. I know its not well formed.
SELECT #xmlString= CAST('<root><Section> ID =' + REPLACE(REPLACE ('20211µ1¶20212µ2', CHAR(182),
'</Section><Section> ID ='),CHAR(181), ' Slno=') + '</Section></root>' AS XML)
This is the pattern which I need to display like this.
<root>
<sections id="20211" slno="1" ></sections>
<sections id="20215" slno="2" ></sections>
</root>
declare #s varchar(50) = '20211µ1¶20212µ2'
declare #xmlString xml
;with C as
(
select T.N.value('value[1]', 'int') as id,
T.N.value('value[2]', 'int') as slno
from (select cast('<item><value>'+replace(replace(#s, 'µ','</value><value>'), '¶','</value></item><item><value>')+'</value></item>' as xml)) as X(XMLCol)
cross apply X.XMLCol.nodes('item') as T(N)
)
select #xmlString =
(
select C.id as [#id] ,
C.slno as [#slno]
from C
for xml path('sections'), root('root'), type
)
select #xmlString
Result:
<root>
<sections id="20211" slno="1" />
<sections id="20212" slno="2" />
</root>