I'm trying to parse the XML data coming from the SQL Server. But although I tried many ways, I could not succeed.
When I run the script it does not give an error but returns a not record
DECLARE #xmlData XML
SET #xmlData = '<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
<faultcode>S:VersionMismatch</faultcode>
<faultstring>Couldnt create SOAP message. Expecting Envelope in namespace http://schemas.xmlsoap.org/soap/envelope/, but got null </faultstring>
</S:Fault>
</S:Body>
</S:Envelope>
'
SET #xmlData = (SELECT #xmlData.query('declare default element namespace "http://schemas.xmlsoap.org/soap/envelope/";
/Envelope/Body'))
SELECT #xmlData
SELECT b.value('(./Fault/faultcode/text())[1]', 'Varchar(50)') AS [Name]
FROM #xmlData.nodes('/Body') AS a (b)
Using WITH XMLNAMESPACES:
;WITH XMLNAMESPACES('http://schemas.xmlsoap.org/soap/envelope/' AS S)
SELECT b.value('(./S:Fault/faultcode/text())[1]', 'Varchar(50)') AS [Name]
FROM #xmlData.nodes('//S:Body') AS a (b);
db<>fiddle demo
Related
I am trying to get a (for right now) simple XML to feed into a SQL Server table.
The XML is:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfSafeEODBalance xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SafeEODBalance>
<Lane>1</Lane>
<PouchId>06292019053041001</PouchId>
<BusinessDay>6/29/2019</BusinessDay>
<BusinessStartingTime>6/29/2019 5:36:58 AM</BusinessStartingTime>
<BusinessEndingTime>6/30/2019 12:15:55 AM</BusinessEndingTime>
<StartingBalance>0.0000</StartingBalance>
<EndingBalance>8</EndingBalance>
</SafeEODBalance>
<SafeEODBalance>
<Lane>2</Lane>
<PouchId>06292019053042002</PouchId>
<BusinessDay>6/29/2019</BusinessDay>
<BusinessStartingTime>6/29/2019 5:36:58 AM</BusinessStartingTime>
<BusinessEndingTime>6/30/2019 12:15:55 AM</BusinessEndingTime>
<StartingBalance>100.0000</StartingBalance>
<EndingBalance>2</EndingBalance>
</SafeEODBalance>
</ArrayOfSafeEODBalance>
And saved to C:\Users\cj\Documents\EodBalance.xml
I have set up the SQL Server table [dbo].[EndofDay] which has the columns of each of these exactly:
Here is the query I am trying:
INSERT INTO [dbo].[EndofDay] ([PouchID], [Lane], [BusinessDay], BusinessStartingTime, BusinessEndingTime, [StartingBalance], [EndingBalance])
SELECT
MY_XML.SafeEODBalance.query('PouchId').value('.', 'VARCHAR(25)'),
MY_XML.SafeEODBalance.query('Lane').value('.', 'NCHAR(2)'),
MY_XML.SafeEODBalance.query('BusinessDay').value('.', 'DATE'),
MY_XML.SafeEODBalance.query('BusinessStartingTime').value('.', 'DATETIME'),
MY_XML.SafeEODBalance.query('BusinessEndingTime').value('.', 'DATETIME'),
MY_XML.SafeEODBalance.query('StartingBalance').value('.', 'NCHAR(10)'),
MY_XML.SafeEODBalance.query('EndingBalance').value('.', 'NCHAR(10)')
FROM
(SELECT CAST(MY_XML AS XML)
FROM OPENROWSET(BULK 'C:\Users\cj\Documents\EodBalance.xml',SINGLE_BLOB) AS T(MY_XML)) AS T(MY_XML)
CROSS APPLY MY_XML.nodes('SafeEODBalance/SafeEODBalances') AS MY_XML (SafeEODBalance);
When I run this I get:
(0 rows affected)
Completion time: 2019-08-29T16:07:12.3361442-04:00
Which obviously should feed two lines into this, but it is giving nothing in the table.
Here is adjusted working SQL. Just uncomment the INSERT lines when you are ready.
SQL
WITH XmlFile (xmlData) AS
(
SELECT CAST(BulkColumn AS XML)
FROM OPENROWSET(BULK 'C:\Users\cj\Documents\EodBalance.xml', SINGLE_BLOB) AS x
)
--INSERT INTO [dbo].[EndofDay]
--([PouchID], [Lane], [BusinessDay], BusinessStartingTime, BusinessEndingTime, [StartingBalance], [EndingBalance])
SELECT c.value('(PouchId/text())[1]', 'VARCHAR(25)') AS [PouchId]
, c.value('(Lane/text())[1]', 'NCHAR(2)') AS [Lane]
, c.value('(BusinessDay/text())[1]', 'DATE') AS [BusinessDay]
, c.value('(BusinessStartingTime)[1]', 'datetime') AS [BusinessStartingTime]
, c.value('(BusinessEndingTime/text())[1]', 'datetime') AS [BusinessEndingTime]
, c.value('(StartingBalance/text())[1]', 'MONEY') AS [StartingBalance]
, c.value('(EndingBalance/text())[1]', 'MONEY') AS [EndingBalance]
FROM XmlFile CROSS APPLY xmlData.nodes('/ArrayOfSafeEODBalance/SafeEODBalance') AS t(c);
** EDIT ** As pointed out in the comments below, this answer uses legacy functions and SPs so should not be used unless you are running on a pre-2005 version of SQL
Here is a slightly different approach, using a variable to store the XML from OPENROWSET and the stored procedure sp_xml_preparedocument to convert it into an XML document.
Once in XML document form it can be queried using OPENXML(). This has the possible advantage that if you have a large or complex XML structure from which you wish to make several extracts, you can re-use the XML document repeatedly without having to reload the original XML file.
Be sure to remove the XML document using sp_xml_removedocument when you have finished with it to free up the server cache.
-- Load the XML file and convert it to an XML document
DECLARE #XML AS XML, #hXML AS INT;
SELECT #XML = CONVERT(XML, x.BulkColumn)
FROM OPENROWSET(BULK 'C:\Users\cj\Documents\EodBalance.xml\EodBalance.xml', SINGLE_BLOB) AS x;
EXEC sp_xml_preparedocument #hXML OUTPUT, #XML
-- Select data from the XML document
SELECT Lane, PouchID, BusinessDay, BusinessStartingTime, BusinessEndingTime, StartingBalance, EndingBalance
FROM OPENXML(#hXML, 'ArrayOfSafeEODBalance/SafeEODBalance') WITH
(
Lane [varchar](2) 'Lane',
PouchId [varchar](50) 'PouchId',
BusinessDay [date] 'BusinessDay',
BusinessStartingTime [datetime] 'BusinessStartingTime',
BusinessEndingTime [datetime] 'BusinessEndingTime',
StartingBalance [varchar](50) 'StartingBalance',
EndingBalance [varchar](50) 'EndingBalance'
);
-- Remove the XML document from the cache
EXEC sp_xml_removedocument #hXML;
So, I'm trying to create a XML file from a SQL table. I do know of the route of using...
Select * From dbo.[db_name]
FOR XML PATH
But the issue at hand is that the XML styling/formatting is quite odd...
<ID>170607A13</ID>
<MaterialActual>
<MaterialLotID>170607A13</MaterialLotID>
<MaterialActualProperty>
<ID>CreationDate</ID>
<Value>
<ValueString>2017-06-07T12:26:27.667-05:00</ValueString>
</Value>
</MaterialActualProperty>
Therefore, I decided I could go the route of concatenating it and inserting into the XML file. Like so...
DECLARE #NAME varchar(50)
DECLARE #LOCATION varchar(50)
DECLARE #SearchXML xml
SET #SearchXML = '<Root>
<CallerInformation>
<LastName>' + #LOCATION + '</LastName>
<FirstName>' + #NAME + '</FirstName>
</CallerInformation>
</Root>'
SELECT #SearchXML
But when doing this I get returned...
If I could get pointed in the right direction or even a example that would be great!
But the issue at hand is that the XML styling/formatting is quite odd...
What is odd there? The only thing odd I can see is the attempt to solve this on string level...
Your question is missing sample data and expected output. The simple select you provide tells us nothing, the XML you provide is an inclompete fragment and the actual example is something completely different...
Just some hints:
Do not concatenate XML on string level!
please read How to ask a good SQL question
and How to create a MCVE
Your simple example should be done like this:
DECLARE #NAME varchar(50)
DECLARE #LOCATION varchar(50)
DECLARE #SearchXML xml
SET #SearchXML =
(
SELECT #LOCATION AS LastName
,#NAME AS FirstName
FOR XML PATH('CallerInformation'),ROOT('Root'),TYPE
);
SELECT #SearchXML;
This will lead to an almost empty (but valid!) XML, put any value into the variables and you will see the XML filled.
UPDATE: Your odd XML...
Try something like this:
SET #xml=
(
SELECT '170607A13' AS ID
,'170607A13' AS [MaterialActual/MaterialLot]
,'CreationDate' AS [MaterialActual/MaterialActualProperty/ID]
,GETDATE() AS [MaterialActual/MaterialActualProperty/Value/ValueString]
FOR XML PATH('')
);
SELECT #xml
UPDATE 2: Very long XPath...
This is your error: name-length more then 128
DECLARE #xml XML;
--SET #xml=
--(
-- SELECT '170607A13' AS ID
-- ,'170607A13' AS [MaterialActual1234567890/MaterialLot1234567890]
-- ,'CreationDate' AS [MaterialActual1234567890/SomeMore1234567890/EvenMore1234567890/StillMore1234567890/MaterialActualProperty1234567890/ID1234567890]
-- ,GETDATE() AS [MaterialActual1234567890/SomeMore1234567890/EvenMore1234567890/StillMore1234567890/MaterialActualProperty1234567890/ValueString1234567890]
-- FOR XML PATH('')
--);
--SELECT #xml
--This is a solution: nested sub-select:
SET #xml=
(
SELECT '170607A13' AS ID
,'170607A13' AS [MaterialActual1234567890/MaterialLot1234567890]
,(
SELECT
'CreationDate' AS [EvenMore1234567890/StillMore1234567890/MaterialActualProperty1234567890/ID1234567890]
,GETDATE() AS [EvenMore1234567890/StillMore1234567890/MaterialActualProperty1234567890/ValueString1234567890]
FOR XML PATH('SomeMore1234567890'),TYPE
) AS [MaterialActual1234567890]
FOR XML PATH('')
);
SELECT #xml;
UPDATE 3: Your follow-up question in comment
HINT: Avoid follow-up questions. Next time please add a new question!
Both return the result requested:
SELECT 'yyyy-MM-dd''T''HH:mm:ss.SSSXXX' AS [PublishedDate/#format]
,GETDATE() AS PublishedDate
FOR XML PATH('')
SELECT 'yyyy-MM-dd''T''HH:mm:ss.SSSXXX' AS [#format]
,GETDATE() AS [*]
FOR XML PATH('PublishedDate');
In my eyes there's no need for the format. Within XML a datetime should be in this format (which is ISO8601) anyway. This is the standard format...
I have the following xml stored in my database table.
I am trying to extract the Productid from the xml , I have been unsuccessful.
Could you tell me what changes I need to make to make the query work ?
XML :
DECLARE #Response VARCHAR(MAX) = '<Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ProductId xsi:type="xsd:long" xmlns="http://nn.service.eservice_v1">30061</ProductId>
</Response>'
Sql Query :
select
CONVERT(XML,CONVERT(NVARCHAR(max),#Response)).value('(/Response/ProductId)[1]','nvarchar(500)') as ProviderId
You want to store the XML in an XML type instead of converting from varchar. If you are able to strip out all the namespace stuff, the following will work.
DECLARE #Response XML = '<Response><ProductId>30061</ProductId></Response>'
SELECT #Response.value('(//ProductId)[1]','nvarchar(500)') as ProviderId
If you are not able to strip out all the namespace stuff, then you will need to include the WITH XMLNAMESPACES clause
DECLARE #Response XML = '<Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ProductId xsi:type="xsd:long" xmlns="http://nn.service.eservice_v1">30061</ProductId>
</Response>'
;WITH XMLNAMESPACES ('http://nn.service.eservice_v1' as e,
'http://www.w3.org/2001/XMLSchema-instance' as xsi)
SELECT #Response.value('(/Response/e:ProductId)[1]','nvarchar(500)') as ProviderId
I have a database table which is structured as shown below :
TransactionId Product ErrorXML(stored as varchar)
The ErrorXML has the structure below :
<?xml version="1.0" encoding="utf-16"?>
<GetResponse
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Error>
<ErrorCode>1809</ErrorCode>
<Description>Could not generate transaction.</Description>
</Error>
<Success>false</Success>
<ContractNumber />
</GetResponse>
I would like to write a query to extract the ErrorCode element and ErrorDescription element for each of the Errorxml row .
Is there a way I can do it ?
I did some research and tried writing a query something like this and it wouldnt work , gives out a null:
select CONVERT(XML,CONVERT(NVARCHAR(max),ErrorXML)).value('(/GetResponse/Error/Description)[1]','nvarchar(100)') as ErrorDescription
from ErrorLog E
Here's a working SQL Fiddle
The Output
ErrorCode ErrorDescription
1809 Could not generate transaction.
2119 Credit Card Overlimit.Payment Failed.
The SQL
See the SQL fiddle for why we have to use a TABLE variable due to your data being in VARCHAR and not XML datatype.
--SELECT * FROM Transactions
DECLARE #ErrorDataTable TABLE
(
ErrorXml XML NOT NULL,
ErrorCode NVARCHAR(50) NULL,
ErrorDescription NVARCHAR(200) NULL
)
INSERT
INTO #ErrorDataTable(ErrorXml)
SELECT
CONVERT(XML,CONVERT(NVARCHAR(max),T.ErrorXML))
FROM Transactions T
-- SELECT * FROM #ErrorDataTable
SELECT
T.c.value('ErrorCode[1]', 'nvarchar(50)') as ErrorCode
, T.c.value('Description[1]', 'nvarchar(200)') as ErrorDescription
FROM #ErrorDataTable e
OUTER APPLY e.ErrorXml.nodes('/GetResponse/Error') T(c);
Previous Answer (deprecated)
Following Works. I'll try to put a SQLFiddle together.
DECLARE #ErrorXML as VARCHAR(MAX);
DECLARE #x as XML;
SET #ErrorXML ='<?xml version="1.0" encoding="utf-16"?>
<GetResponse
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Error>
<ErrorCode>1809</ErrorCode>
<Description>Could not generate transaction.</Description>
</Error>
<Success>false</Success>
<ContractNumber />
</GetResponse>';
SET #x = CONVERT(XML,CONVERT(NVARCHAR(max),#ErrorXML))
SELECT
T.c.value('ErrorCode[1]', 'nvarchar(50)') as ErrorCode
, T.c.value('Description[1]', 'nvarchar(200)') as ErrorDescription
FROM #x.nodes('/GetResponse/Error') T(c);
RESULTS:
ErrorCode ErrorDescription
1809 Could not generate transaction.
I have declared a #xmldata as xml. How to read it? I tried
declare #xmldata as xml
set #xmldata = <root><row ename='abc' eid='1'/></root>
SELECT #XMLDATA
but it returned an error. I want to fetch eid column from the above xml type.
Try this:
declare #xmldata as xml
set #xmldata = '<root><row ename="abc" eid="1"/></root>'
SELECT
#xmldata.value('(/root/row/#eid)[1]', 'int') AS 'EID'
Update: if you need to select from your table and extract something from the XML column, use this approach:
SELECT
tbl.ID,
tbl.XmlColumn.value('(/root/row/#ename)[1]', 'varchar(25)') AS 'EName'
FROM
dbo.YourTable tbl
WHERE
(...some condition here...)