I want to extract the value from the XML data to columns.
I tried using this:
DECLARE #xml XML
SELECT #xml = Data FROM synergy..XMLData
SELECT
xmlData.Col.value('(column/#value)[1]','varchar(255)') AS 'Artikelen',
xmlData.Col.value('(column/#value)[2]','varchar(255)') AS 'Batchnummer',
xmlData.Col.value('(column/#value)[3]','varchar(255)') AS 'Aantal'
FROM
#XML.nodes ('//table/rows/row/columns') xmldata(Col)
however I'm only getting titles, but no data.
This is what the XML looks like:
<?xml version="1.0" encoding="utf-16"?>
<table>
<id>{941D5F5A-156A-4F19-A3B0-111E9825707B}</id>
<rows>
<row>
<columns>
<column name="Artikelen" value="102535.A.M2" type="System.String" />
<column name="Batchnummer" value="19D1739/133" type="System.String" />
<column name="Aantal" value="8" type="System.Int32" />
<column name="Opmerkingen" value="te weinig" type="System.String" />
<column name="Selecteren" value="1" type="System.String" />
<column name="DefaultKey" value="1" type="System.Int32" />
</columns>
</row>
</rows>
<key>DefaultKey</key>
<total>0</total>
<AddOnKey>0</AddOnKey>
<data />
<parameters />
</table>
It is better to shred XML and get needed data by referring to the named attributes instead of their position.
SQL
DECLARE #xml XML = '
<table>
<id>{941D5F5A-156A-4F19-A3B0-111E9825707B}</id>
<rows>
<row>
<columns>
<column name="Artikelen" value="102535.A.M2" type="System.String"/>
<column name="Batchnummer" value="19D1739/133" type="System.String"/>
<column name="Aantal" value="8" type="System.Int32"/>
<column name="Opmerkingen" value="te weinig" type="System.String"/>
<column name="Selecteren" value="1" type="System.String"/>
<column name="DefaultKey" value="1" type="System.Int32"/>
</columns>
</row>
</rows>
<key>DefaultKey</key>
<total>0</total>
<AddOnKey>0</AddOnKey>
<data/>
<parameters/>
</table>';
SELECT col.value('(column[#name="Artikelen"]/#value)[1]','VARCHAR(255)') AS [Artikelen]
, col.value('(column[#name="Batchnummer"]/#value)[1]','VARCHAR(255)') AS [Batchnummer]
, col.value('(column[#name="Aantal"]/#value)[1]','INT') AS [Aantal]
FROM #XML.nodes ('/table/rows/row/columns') AS tab(col);
Output
+-------------+-------------+--------+
| Artikelen | Batchnummer | Aantal |
+-------------+-------------+--------+
| 102535.A.M2 | 19D1739/133 | 8 |
+-------------+-------------+--------+
Related
This question already has answers here:
Import 'xml' into Sql Server
(5 answers)
Closed 5 years ago.
I want to import below XML file into SQL table. (SQL Server 2008R2)
<table>
<id>{72cbb5ab-dbb3-4de7-9010-5dd1192a1851}</id>
<rows>
<row>
<columns>
<column name="itemcode" value="0984-22-301" type="System.String" />
<column name="date" value="08-November-2017" type="System.DateTime" />
<column name="amount" value="10" type="System.Decimal" />
<column name="DefaultKey" value="1" type="System.Int32" />
</columns>
</row>
<row>
<columns>
<column name="itemcode" value="0984-33-101" type="System.String" />
<column name="date" value="08-November-2017" type="System.DateTime" />
<column name="amount" value="11" type="System.Decimal" />
<column name="DefaultKey" value="2" type="System.Int32" />
</columns>
</row>
</rows>
<key>DefaultKey</key>
<total>0</total>
<data />
<parameters />
</table>
It should look like a sql table with columns id, itemcode, date and amount.
How should my query look like?
Solved the question.
declare #xmltable table (data xml)
insert into #xmltable (data)
select DATA from [MyData]..myxml
SELECT
LineId = c.value('id[1]', 'nvarchar(max)'),
ColumnItemCode = l.value('(columns/column[#name="itemcode"]/#value)[1]', 'varchar(20)'),
ColumnDate = l.value('(columns/column[#name="date"]/#value)[1]', 'varchar(20)'),
ColumnAmount = l.value('(columns/column[#name="amount"]/#value)[1]', 'varchar(20)')
FROM
#xmltable x
CROSS APPLY data.nodes('table') t(c)
CROSS APPLY data.nodes('table/rows/row') b(l)
This resulted in:
LineId ColumnItemCode ColumnDate ColumnAmount
{72cbb5ab-dbb3-4de7-9010-5dd1192a1851} 0984-22-301 08-November-2017 10
{72cbb5ab-dbb3-4de7-9010-5dd1192a1851} 0984-33-101 08-November-2017 11
Thanks for your help.
I'm working with XML string shown below.
I have to update the XML string as follows:
If the XML string contains 1000 records or more, it kills the query
If the XML string contains < 1000 records, let it continue.
How can I do this?
example data
<root xmlns:json="http://james.newtonking.com/projects/json">
<row json:Array="true" RowNumber="1">
<Column json:Array="true" Name="Number" Value="1" />
<Column json:Array="true" Name="HourFrom" Value="13.2" />
<Column json:Array="true" Name="HourTo" Value="13.3" />
<Column json:Array="true" Name="Rate" Value="0.895" />
</row>
<row json:Array="true" RowNumber="2">
<Column json:Array="true" Name="Number" Value="1" />
<Column json:Array="true" Name="HourFrom" Value="13.3" />
<Column json:Array="true" Name="HourTo" Value="13.4" />
<Column json:Array="true" Name="Rate" Value="0.907" />
</row>
</root>
Temp table creation
CREATE TABLE #xmltable(
Id INT Identity (1,1) PRIMARY KEY CLUSTERED,
DataValue XML
);
CREATE PRIMARY XML INDEX indexratesheet ON #xmltable
(
DataValue
)
Inserting data into table
INSERT INTO (DataValue ) VALUES(TheXMLfromAbove)
updating the XML string in the table
DECLARE #i INT 1
WHILE(#i<=1000)
BEGIN
UPDATE #xmltable SET DataValue.modify('insert <Column Name="ValidationComments" Value="{sql:variable("#validationcomments")}"></Column>
into (/root/row[#i=sql:variable("#i")])[1]')
SET #i=#i+1
END
If you have to keep this with XML it should be much faster to shred the whole XML into a derivedTable and re-build it from scratch.
Try this:
CREATE TABLE #xmltable(
Id INT Identity (1,1) PRIMARY KEY CLUSTERED,
DataValue XML
);
CREATE PRIMARY XML INDEX indexratesheet ON #xmltable
(
DataValue
);
--Your test XML
INSERT INTO #xmltable (DataValue ) VALUES(N'<root xmlns:json="http://james.newtonking.com/projects/json">
<row json:Array="true" RowNumber="1">
<Column json:Array="true" Name="Number" Value="1" />
<Column json:Array="true" Name="HourFrom" Value="13.2" />
<Column json:Array="true" Name="HourTo" Value="13.3" />
<Column json:Array="true" Name="Rate" Value="0.895" />
</row>
<row json:Array="true" RowNumber="2">
<Column json:Array="true" Name="Number" Value="1" />
<Column json:Array="true" Name="HourFrom" Value="13.3" />
<Column json:Array="true" Name="HourTo" Value="13.4" />
<Column json:Array="true" Name="Rate" Value="0.907" />
</row>
</root>');
--The query to shred it
SELECT r.value(N'#RowNumber','int') AS RowNumber
,r.value(N'(Column[#Name="Number"]/#Value)[1]','int') AS Number
,r.value(N'(Column[#Name="HourFrom"]/#Value)[1]','decimal(10,4)') AS HourFrom
,r.value(N'(Column[#Name="HourTo"]/#Value)[1]','decimal(10,4)') AS HourTo
,r.value(N'(Column[#Name="Rate"]/#Value)[1]','decimal(10,4)') AS Rate
INTO #derivedTable
FROM #xmltable AS t
CROSS APPLY t.DataValue.nodes(N'/root/row') AS A(r);
--The query to re-build it
WITH XMLNAMESPACES('http://james.newtonking.com/projects/json' AS json)
SELECT 'true' AS [#json:Array]
,t.RowNumber AS [#RowNumber]
,'true' AS [Column/#json:Array]
,'Number' AS [Column/#Name]
,t.Number AS [Column/#Value]
,''
,'true' AS [Column/#json:Array]
,'HourFrom' AS [Column/#Name]
,t.HourFrom AS [Column/#Value]
,''
,'true' AS [Column/#json:Array]
,'HourTo' AS [Column/#Name]
,t.HourTo AS [Column/#Value]
,''
,'true' AS [Column/#json:Array]
,'Rate' AS [Column/#Name]
,t.Rate AS [Column/#Value]
,''
,'ValidationComments' AS [Column/#Name]
,'SomeValue' AS [Column/#Value]
FROM #derivedTable AS t
FOR XML PATH('row'),ROOT('root');
--Clean up (carefull with real data!)
GO
DROP TABLE #derivedTable;
DROP TABLE #xmltable
This is the result
<root xmlns:json="http://james.newtonking.com/projects/json">
<row json:Array="true" RowNumber="1">
<Column json:Array="true" Name="Number" Value="1" />
<Column json:Array="true" Name="HourFrom" Value="13.2000" />
<Column json:Array="true" Name="HourTo" Value="13.3000" />
<Column json:Array="true" Name="Rate" Value="0.8950" />
<Column Name="ValidationComments" Value="SomeValue" />
</row>
<row json:Array="true" RowNumber="2">
<Column json:Array="true" Name="Number" Value="1" />
<Column json:Array="true" Name="HourFrom" Value="13.3000" />
<Column json:Array="true" Name="HourTo" Value="13.4000" />
<Column json:Array="true" Name="Rate" Value="0.9070" />
<Column Name="ValidationComments" Value="SomeValue" />
</row>
</root>
UPDATE
Try this query, it will work for all different column lists, but it will repeat the namespace declaration. This is not wrong, but very annoying. At the moment I do not have the time to think about a hack. Let me know, if this works for you.
WITH XMLNAMESPACES('http://james.newtonking.com/projects/json' AS json)
,CTE AS
(
SELECT r.value(N'#RowNumber','int') AS RowNumber
,r.query('./*') AS TheContent
FROM #xmltable AS t
CROSS APPLY t.DataValue.nodes(N'/root/row') AS A(r)
)
SELECT CTE.TheContent AS [*]
,'ValidationComments' AS [Column/#Name]
,'SomeValue' AS [Column/#Value]
FROM CTE
FOR XML PATH('row'),ROOT('root')
I needed to turn this xml from this:
<Row>
<Columns>
<Column>
<Value>BB1</Value>
<Name>Location</Name>
</Column>
<Column>
<Value>1593338</Value>
<Name>Location_Key</Name>
</Column>
<Column>
<Value>0</Value>
<Name>Quantity</Name>
</Column>
</Columns>
</Row>
<Row>
<Columns>
<Column>
<Value>DR11 40</Value>
<Name>Location</Name>
</Column>
<Column>
<Value>1593251</Value>
<Name>Location_Key</Name>
</Column>
<Column>
<Value>0</Value>
<Name>Quantity</Name>
</Column>
</Columns>
</Row>
To this table with these columns and rows
(Location) (Location_Key) (Quantity)
BB1 1593338 0
DR11 1593251 0
Using Sql Server
I have been trying for weeks but to no avail.
Any answer would be greatly aprreciated.
Try this:
DECLARE #input XML = '<Row>
<Columns>
<Column>
<Value>BB1</Value>
<Name>Location</Name>
</Column>
<Column>
<Value>1593338</Value>
<Name>Location_Key</Name>
</Column>
<Column>
<Value>0</Value>
<Name>Quantity</Name>
</Column>
</Columns>
</Row>
<Row>
<Columns>
<Column>
<Value>DR11 40</Value>
<Name>Location</Name>
</Column>
<Column>
<Value>1593251</Value>
<Name>Location_Key</Name>
</Column>
<Column>
<Value>0</Value>
<Name>Quantity</Name>
</Column>
</Columns>
</Row>'
SELECT
Location = xc.value('(Column[Name="Location"]/Value)[1]', 'varchar(20)'),
LocationKey = xc.value('(Column[Name="Location_Key"]/Value)[1]', 'varchar(20)'),
Quantity = xc.value('(Column[Name="Quantity"]/Value)[1]', 'int')
FROM
#input.nodes('/Row/Columns') AS XT(XC)
This gives you an output something like this:
You can use this SELECT inside an INSERT INTO ..... or do whatever you like to do with it.
I have an XML Query like this:
<ChangeSet xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Change DateTime="2011-12-02T09:01:58.3615661-08:00" UserId="3123">
<Table ChangeType="Insert" Name="EVNT_LN_AFF">
<Keys>
<Key FieldName="DIR_CD" Value="NB" />
<Key FieldName="LN_ID" Value="A" />
<Key FieldName="EVNT_ID" Value="10T000289" />
</Keys>
<ChangedFields>
<Field FieldName="DIR_CD" Previous="" Current="NB" />
<Field FieldName="LN_ID" Previous="" Current="A" />
<Field FieldName="EVNT_ID" Previous="" Current="10T000289" />
<Field FieldName="UD_DTTM" Previous="" Current="12/2/2011 9:01:59 AM" />
<Field FieldName="UD_USER_ID" Previous="" Current="3123" />
</ChangedFields>
</Table>
(The query goes on)
Now I want to use a statement like this:
SELECT TOP 1000 [CHG_LOG_ID]
, [EVNT_ID]
, [DATA_XML_TXT]
, [UD_DTTM]
FROM [MY_PROJ].[dbo].[EVNT_CHG_LOG]
WHERE DATA_XML_TXT.value('(/ChangeSet/Change/Table/ChangedFields/UD_USER_ID)[0]','varchar(50)') like '%3123%'
But when I execute the query, I don't get any results.
I tested the following XQuery, and it should give you what you need:
SELECT TOP 1000 [CHG_LOG_ID]
, [EVNT_ID]
, [DATA_XML_TXT]
, [UD_DTTM]
FROM [MY_PROJ].[dbo].[EVNT_CHG_LOG]
WHERE DATA_XML_TXT.value('(/ChangeSet/Change/Table/ChangedFields/Field[#FieldName="UD_USER_ID"]/#Current)[1]','varchar(50)') like '%3123%'
Note: Indexing for XQuery starts at 1 instead of 0
I am creating a comma separated value of columns specified in the dbName attribute of the XML below. Now I want to concatenate those columns on the basis of the Position attribute.
DECLARE #varXML AS XML =
'<gridFormat>
<column property="FacilityInternalID" dbName="Pname" HeaderText="TAT Health" IsVisible="1" Position="1" />
<column property="FacilityInternalID" dbName="Priority" HeaderText="Priority" IsVisible="1" Position="2" />
<column property="FacilityInternalID" dbName="JobID" HeaderText="Job Number" IsVisible="1" Position="3" />
<column property="FacilityInternalID" dbName="Status" HeaderText="Status" IsVisible="1" Position="6" />
<column property="FacilityInternalID" dbName="name" HeaderText="Customer" IsVisible="1" Position="4" />
<column property="FacilityInternalID" dbName="sname" HeaderText="Facility " IsVisible="1" Position="5" />
</gridFormat>'
PRINT #varXML
This is the query by which I am generating CSV of columns. I have to use it as a select list.
SELECT #ColumnsToDisplay = LEFT(MyCsvList, LEN(MyCsvList) - 1)
FROM ( SELECT ( SELECT row.value('#property',
'varchar(200)') + ', ' AS [text()]
FROM #varXML.nodes('gridFormat/column')
AS d ( row )
FOR
XML PATH('')
) AS MyCsvList
) AS MyCsvListFinal
SET #SQL = 'SELECT ' + #ColumnsToDisplay
+ ' FROM JobListingDetails'
The result should be
select Pname,Priority,JobID,name,sname,status FROM JobListingDetails.
Please help.
This should work:
Note that you need to read the dbName attribute.
[EDIT] Updated to include order by. Basicaly you also read the Postion attribute from xml, then use that in the ORDER BY:
declare #ColumnsToDisplay varchar(max)
DECLARE #varXML AS XML
set #varxml =
'<gridFormat>
<column property="FacilityInternalID" dbName="Pname" HeaderText="TAT Health" IsVisible="1" Position="1" />
<column property="FacilityInternalID" dbName="Priority" HeaderText="Priority" IsVisible="1" Position="2" />
<column property="FacilityInternalID" dbName="JobID" HeaderText="Job Number" IsVisible="1" Position="3" />
<column property="FacilityInternalID" dbName="Status" HeaderText="Status" IsVisible="1" Position="6" />
<column property="FacilityInternalID" dbName="name" HeaderText="Customer" IsVisible="1" Position="4" />
<column property="FacilityInternalID" dbName="sname" HeaderText="Facility " IsVisible="1" Position="5" />
</gridFormat>'
SELECT #ColumnsToDisplay = COALESCE(#ColumnsToDisplay + ',', '') + dbName
FROM
(
SELECT row.value('#dbName','varchar(200)') AS dbName, row.value('#Position','int') as pos
FROM #varXML.nodes('gridFormat/column')
AS d ( row )
) csv
order by pos
select 'SELECT ' + #ColumnsToDisplay + ' FROM JobListingDetails'
See this article for a cool way to do string concatenation without using a cursor.
It's under the "Replacing the cursor with a SET based approach" section.