I've read all of the other posts on this subject but none are working for me. This one is the closest CONVERTING SQL NVARCHAR(MAX) TO XML
So, I've modified that code to try and fit my situation. I have a nvarchar(max) column that contains XML data as one big long string. It's not my database, so I can't change the datatype to XML. The next best thing is to create a query and cast it as XML. Here is my code:
IF OBJECT_ID('tempdb..#XML_Dummy') IS NOT NULL DROP TABLE #XML_Dummy
GO
CREATE TABLE #XML_Dummy
(
[ID] [INT] IDENTITY(1, 1)
NOT NULL ,
[XMLValue] [NVARCHAR](MAX) NULL
);
GO
INSERT INTO #XML_Dummy
(
[XMLValue]
)
select top 10 xmlcol from MyTable
GO
SELECT
b.x.value('(/Proponix/Header/SubHeader/InstrumentID)[1]', 'varchar(max)')
FROM
#XML_Dummy a
CROSS APPLY (
SELECT
CAST(CAST ([XMLValue] AS VARCHAR(MAX)) AS XML) x
) b;
IF OBJECT_ID('tempdb..#XML_Dummy') IS NOT NULL DROP TABLE #XML_Dummy;
I'm not sure why I'm getting all NULLS back. I want to return the InstrumentID. Here is an excerpt of my XML:
<?xml version="1.0"?>
<Proponix>
<Header>
Header stuff
</Header>
<SubHeader>
<InstrumentID>BS6000000001</InstrumentID>
</SubHeader>
A lot more fields
What am I missing? This is my first time working with XML in SQL server.
SubHeader is not a child of Header in your example. Try:
b.x.value('(/Proponix/SubHeader/InstrumentID)[1]', 'varchar(max)')
You try to find the SubHeader as a child of Header but it is a sibling...
Try this:
EDIT: changed #x to simulate a table with a nvarchar-column containing different xml_msg values:
EDIT2: adapted according to calls the OP showed in chat
WITH ConvertedToXML AS
(
SELECT xml_msg AsVarchar
,CAST(xml_msg AS XML) AS AsXml
FROM myTable
)
SELECT ConvertedToXML.AsVarchar
,ConvertedToXML.AsXml
,ConvertedToXML.AsXml.value('(/Proponix/SubHeader/InstrumentID)[1]', 'varchar(max)') AS InstrumentID
FROM ConvertedToXML
--old Text
declare #x table(xml_msg nvarchar(max));
insert into #x VALUES
('<?xml version="1.0"?>
<Proponix>
<Header>
Header stuff
</Header>
<SubHeader>
<InstrumentID>BS6000000001</InstrumentID>
</SubHeader>
</Proponix>')
,('<?xml version="1.0"?>
<Proponix>
<Header>
Header stuff
</Header>
<SubHeader>
<InstrumentID>BS6000000002</InstrumentID>
</SubHeader>
</Proponix>')
,('<?xml version="1.0"?>
<Proponix>
<Header>
Header stuff
</Header>
<SubHeader>
<InstrumentID>BS6000000003</InstrumentID>
</SubHeader>
</Proponix>');
WITH ConvertedToXML AS
(
SELECT TOP 10 CAST(xml_msg AS XML) AS AsXml FROM #x
)
SELECT
ConvertedToXML.AsXml.value('(/Proponix/SubHeader/InstrumentID)[1]', 'varchar(max)')
FROM ConvertedToXML
Related
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
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;
I have multiple XML files with the same structure, I have imported them to SQL Server 2017 with the following commands:
DDL:
CREATE DATABASE xmlFiles
GO
USE xmlFiles
CREATE TABLE tblXMLFiles (IntCol int, XmlData xml);
GO
DML:
USE xmlFiles
INSERT INTO [dbo].[tblXMLFiles](XmlData) SELECT * FROM OPENROWSET(BULK 'C:\xmls\1.xml', SINGLE_BLOB) AS x;
INSERT INTO [dbo].[tblXMLFiles](XmlData) SELECT * FROM OPENROWSET(BULK 'C:\xmls\2.xml', SINGLE_BLOB) AS x;
…
INSERT INTO [dbo].[tblXMLFiles](XmlData) SELECT * FROM OPENROWSET(BULK 'C:\xmls\N.xml', SINGLE_BLOB) AS x;
Now I want to query the data:
USE xmlFiles
GO
DECLARE #XML AS XML, #hDoc AS INT, #SQL NVARCHAR (MAX)
SELECT #XML = XmLData FROM tblXMLFiles
EXEC sp_xml_preparedocument #hDoc OUTPUT, #XML
SELECT Surname , GivenNames
FROM OPENXML(#hDoc, 'article/ref-list/ref/mixed-citation')
WITH
(
Surname [varchar](100) 'string-name/surname',
GivenNames [varchar](100) 'string-name/given-names'
)
EXEC sp_xml_removedocument #hDoc
GO
The query is working, but the problem is that it returns the data only when there is only one row in a data source table — tblXMLFiles. If I add more than one row, I get empty result set.
Important:
The situation is changing if I add to the outer SELECT clause (SELECT #XML = XmLData…) the TOP statement, then it returns the queried data of the specific row number, according to the TOP value.
How can I retrieve the data not only when there is one line in the table, but many rows?
FROM OPENXML with the corresponding SPs to prepare and to remove a document is outdated and should not be used any more. Rather use the appropriate methods the XML data type provides.
Without an example of your XML it is quite difficult to offer a solution, but my magic crystal ball tells me, that it might be something like this:
SELECT f.IntCol
,mc.value('(string-name/surname)[1]','nvarchar(max)') AS Surname
,mc.value('(string-name/given-names)[1]','nvarchar(max)') AS GivenNames
FROM dbo.tblXMLFiles AS f
OUTER APPLY f.XmlData.nodes('article/ref-list/ref/mixed-citation') AS A(mc)
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 an xml file where the ordering of nodes is important, like this one:
<Queue>
<User name="Bob"/>
<User name="Jane"/>
<User name="Douglas"/>
<User name="Samantha"/>
</Queue>
I'm using OPENXML to store these nodes in a table variable. How can I ensure that the node order is preserved when I insert into the table variable?
Note, I'm using OPENXML and not xquery so this is not a duplicate of: Finding node order in XML document in SQL server
I'm currently doing the following, relying on the 'mp:id' to provide the ordering.
DECLARE #xmltext NVARCHAR(MAX)
SET #xmltext =
N'
<Queue>
<User name="Bob"/>
<User name="Jane"/>
<User name="Douglas"/>
<User name="Samantha"/>
</Queue>';
DECLARE #xmlObjectHandler INT;
-- Set up XML and the appropriate namespace(s) we'll be using
EXEC sp_xml_preparedocument #xmlObjectHandler OUTPUT, #xmltext;
DECLARE #TUserQueue TABLE (
Ordinal INT IDENTITY(1,1),
UserName NVARCHAR(200)
)
INSERT INTO #TUserQueue
SELECT
UserName
FROM
OPENXML(#xmlObjectHandler, '/Queue/User')
WITH (
NodeId INT '#mp:id',
UserName NVARCHAR(200) '#name'
) AS users
ORDER BY users.NodeId;
SELECT * FROM #TUserQueue