T-SQL convert xml field to multi column table - sql

I am trying to convert data from a xml field into a table. I have found multiple solutions on this website, but none of them seem to give me exactly what I need.
The xml looks like this:
<table>
<id>{100}</id>
<rows>
<row>
<columns>
<column name="cur" value="EUR" type="System.String" />
<column name="item" value="Item a" type="System.String" />
<column name="price" value="2.5" type="System.Decimal" />
<column name="qty" value="20" type="System.Int32" />
<column name="Key" value="1" type="System.Int32" />
</columns>
</row>
<row>
<columns>
<column name="cur" value="EUR" type="System.String" />
<column name="item" value="Item b" type="System.String" />
<column name="price" value="30" type="System.Decimal" />
<column name="qty" value="30" type="System.Int32" />
<column name="Key" value="2" type="System.Int32" />
</columns>
</row>
</rows>
<key>Key</key>
</table>
I would like the result to look like this:
id key cur item price qty
100 1 EUR Item a 2.5 20
100 2 EUR Item b 30 30
I hope someone can help me.

Try it like this:
DECLARE #x XML=
'<table>
<id>{100}</id>
<rows>
<row>
<columns>
<column name="cur" value="EUR" type="System.String" />
<column name="item" value="Item a" type="System.String" />
<column name="price" value="2.5" type="System.Decimal" />
<column name="qty" value="20" type="System.Int32" />
<column name="Key" value="1" type="System.Int32" />
</columns>
</row>
<row>
<columns>
<column name="cur" value="EUR" type="System.String" />
<column name="item" value="Item b" type="System.String" />
<column name="price" value="30" type="System.Decimal" />
<column name="qty" value="30" type="System.Int32" />
<column name="Key" value="2" type="System.Int32" />
</columns>
</row>
</rows>
<key>Key</key>
</table>';
SELECT #x.value('(/table/id)[1]','varchar(max)') AS id --are the curly brackets there on purpose?
,Rw.value('(columns/column[#name="Key"]/#value)[1]','int') AS [key]
,Rw.value('(columns/column[#name="cur"]/#value)[1]','varchar(max)') AS cur
,Rw.value('(columns/column[#name="item"]/#value)[1]','varchar(max)') AS item
,Rw.value('(columns/column[#name="price"]/#value)[1]','decimal(10,4)') AS price
,Rw.value('(columns/column[#name="qty"]/#value)[1]','int') AS qty
FROM #x.nodes('/table/rows/row') AS A(Rw)

Related

Querying XML data stored in SQL Server column

My table is XMLData with an XML column XMLField.
The data in the column looks like this:
<table>
<id>{9ebef1ed-51f6-4160-b342-40fd1bf311c5}</id>
<rows>
<row>
<columns>
<column name="Batch" value="Test Batch 123" type="System.String" />
<column name="PartNo" value="Sample123" type="System.String" />
<column name="Note" value="Slight Color Variants" type="System.String" />
<column name="ShipDate" value="05-August-2018" type="System.DateTime" />
<column name="Qty" value="2" type="System.Int32" />
<column name="DefaultKey" value="1" type="System.Int32" />
</columns>
</row>
<row>
<columns>
<column name="Batch" value="Second Batch" type="System.String" />
<column name="PartNo" value="SampleXyz" type="System.String" />
<column name="Note" value="Release Date TBD" type="System.String" />
<column name="ShipDate" value="01-September-2018" type="System.DateTime" />
<column name="Qty" value="1" type="System.Int32" />
<column name="DefaultKey" value="2" type="System.Int32" />
</columns>
</row>
</rows>
<key>DefaultKey</key>
<total>0</total>
<data />
<parameters />
</table>
I would like to query Batch, PartNo, Note, ShipDate, Qty, DefaultKey and retrieve the values.
Thank you
Try something like this:
SELECT
Batch = XC.value('(column[#name="Batch"]/#value)[1]', 'varchar(50)'),
PartNo = XC.value('(column[#name="PartNo"]/#value)[1]', 'varchar(50)'),
Note = XC.value('(column[#name="Note"]/#value)[1]', 'varchar(50)'),
ShipDate = XC.value('(column[#name="ShipDate"]/#value)[1]', 'varchar(50)'),
Qty = XC.value('(column[#name="Qty"]/#value)[1]', 'int'),
DefaultKey = XC.value('(column[#name="DefaultKey"]/#value)[1]', 'int')
FROM
dbo.XmlData
CROSS APPLY
XmlField.nodes('/table/rows/row/columns') AS XT(XC)
It basically takes the XmlField column's XML, and gets a "virtual" table of XML fragments according to the XPath in the .nodes() expression. From there, it reaches into those XML fragments returned, and pulls out the individual values you're interested in.

Stored Procedure with a xml data

I am trying to get the data from a field in a SQL server table. It is stored as a xml and I wanted to get each node value in a different row.
The xml sample is like this:
<id>{a75f61ce-6627-489f-83bb-d03fc880b764}</id>
<rows>
<row>
<columns>
<column name="ec_date" value="15-November-2017" type="System.DateTime" />
<column name="ec_amount" value="160" type="System.Decimal" />
<column name="ec_description" value="viaje en coche" type="System.String" />
<column name="ec_factura" value="0" type="System.String" />
<column name="ec_item" value="105.01" type="System.String" />
<column name="DefaultKey" value="1" type="System.Int32" />
</columns>
</row>
<row>
<columns>
<column name="ec_date" value="16-November-2017" type="System.DateTime" />
<column name="ec_amount" value="2.55" type="System.Decimal" />
<column name="ec_description" value="2 horas de parkin" type="System.String" />
<column name="ec_factura" value="0" type="System.String" />
<column name="ec_item" value="15.04" type="System.String" />
<column name="DefaultKey" value="2" type="System.Int32" />
</columns>
</row>
<row>
<columns>
<column name="ec_date" value="17-November-2017" type="System.DateTime" />
<column name="ec_amount" value="200" type="System.Decimal" />
<column name="ec_description" value="taxi a burgos" type="System.String" />
<column name="ec_factura" value="0" type="System.String" />
<column name="ec_item" value="15.06" type="System.String" />
<column name="DefaultKey" value="3" type="System.Int32" />
</columns>
</row>
</rows>
Can somebody tell me how to get each < row > element in a sql row with each different column values?
Thank you all
In order to parse an Xml column in a table, you'll want to use XQuery. Here's an example of how you would go about this - it will return one row per row xml element:
SELECT
Rows.col.value('(column[#name="ec_date"]/#value)[1]',
'DATE') AS EcDate,
Rows.col.value('(column[#name="ec_amount"]/#value)[1]',
'decimal(10,2)') AS EcAmount,
Rows.col.value('(column[#name="ec_description"]/#value)[1]',
'varchar(max)') AS EcDescription
-- .. etc
FROM
MyTable mt
CROSS APPLY
mt.XmlCol.nodes('//rows/row/columns')
AS Rows(col);
(column[#name="ec_date"]/#value)[1] loosely translates to "find me the first column element with the name attribute of value ec_date and return me the value of the value attribute.
With a Sql Fiddle here
Obligatory Caveats
Although the xml column attribute names and types seem consistent, it seems there is a type system embedded in the data - i.e. an attempt to provide the ability to dynamically change the type of the columns would make this very messy indeed.
On the other hand, of all data in your Xml document has a strong schema, then I would argue that Xml is a poor choice for data modelling - it would have been better to have normalized out row into it's own table. Xml is a verbose format, which repeats the schema (i.e. wastes space), and can be difficult to parse and filter.
I think you can use OPENXML
DECLARE #idoc int, #doc varchar(MAX)
SET #doc='<id>{a75f61ce-6627-489f-83bb-d03fc880b764}</id>
<rows>
<row>
<columns>
<column name="ec_date" value="15-November-2017" type="System.DateTime" />
<column name="ec_amount" value="160" type="System.Decimal" />
<column name="ec_description" value="viaje en coche" type="System.String" />
<column name="ec_factura" value="0" type="System.String" />
<column name="ec_item" value="105.01" type="System.String" />
<column name="DefaultKey" value="1" type="System.Int32" />
</columns>
</row>
<row>
<columns>
<column name="ec_date" value="16-November-2017" type="System.DateTime" />
<column name="ec_amount" value="2.55" type="System.Decimal" />
<column name="ec_description" value="2 horas de parkin" type="System.String" />
<column name="ec_factura" value="0" type="System.String" />
<column name="ec_item" value="15.04" type="System.String" />
<column name="DefaultKey" value="2" type="System.Int32" />
</columns>
</row>
<row>
<columns>
<column name="ec_date" value="17-November-2017" type="System.DateTime" />
<column name="ec_amount" value="200" type="System.Decimal" />
<column name="ec_description" value="taxi a burgos" type="System.String" />
<column name="ec_factura" value="0" type="System.String" />
<column name="ec_item" value="15.06" type="System.String" />
<column name="DefaultKey" value="3" type="System.Int32" />
</columns>
</row>
</rows>'
-- delete <id>
SET #doc=STUFF(#doc,1,47,'')
EXEC sp_xml_preparedocument #idoc OUTPUT, #doc;
SELECT *
FROM OPENXML(#idoc,'/rows/row/columns',2)
WITH (ec_date date './column[1]/#value',
ec_amount float './column[2]/#value',
ec_description varchar(200) './column[3]/#value',
ec_factura int './column[4]/#value',
ec_item float './column[5]/#value',
DefaultKey int './column[6]/#value');
EXEC sp_xml_removedocument #idoc;
GO
I deleted <id>{a75f61ce-6627-489f-83bb-d03fc880b764}</id> first of all.

XML to SQL Columns and value

I have this xml value as a column in a table:
<?xml version="1.0" encoding="utf-16"?>
<table>
<id>{44f2e878-64a6-4217-acba-2d986cbb0f93}</id>
<rows>
<row>
<columns>
<column name="wc_Bin" value="BIN-2" type="System.String" />
<column name="wc_replacebin" value="BIN-3" type="System.String" />
<column name="wc_client" value="70360" type="System.String" />
<column name="ec_weight" value="150" type="System.Decimal" />
<column name="DefaultKey" value="1" type="System.Int32" />
</columns>
</row>
<row>
<columns>
<column name="wc_Bin" value="BIN-3" type="System.String" />
<column name="wc_replacebin" value="Bin-1" type="System.String" />
<column name="wc_client" value="1000058" type="System.String" />
<column name="ec_weight" value="250" type="System.Decimal" />
<column name="DefaultKey" value="2" type="System.Int32" />
</columns>
</row>
<row>
<columns>
<column name="wc_Bin" value="Bin-1" type="System.String" />
<column name="wc_replacebin" value="BIN-2" type="System.String" />
<column name="wc_client" value="1000006" type="System.String" />
<column name="ec_weight" value="100" type="System.Decimal" />
<column name="DefaultKey" value="3" type="System.Int32" />
</columns>
</row>
</rows>
<key>DefaultKey</key>
<total>0</total>
<data />
<parameters />
</table>
I want column name from <column name="wc_bin"> and its value from value="" attribute. Desired output is:
wc_Bin Replace_Bin wc_Client ec_weight
----------------------------------------------
Bin-2 Bin-3 70360 350
bin-3 Bin-1 1000058 250
Bin-1 Bin-2 100006 100
Any help appreciated.

Using the Propel ORM, how would one delete all related records of an object?

I have a pretty simple Propel question. I'm storing leads in a database. Those leads have one or more community interests. The tables I'm using are named, 'lead', 'community', and a 'lead_communities' join table. What's the best way to delete all of a lead's community interests?
Here are some more details. The Propel schema looks like this:
<table name="community">
<column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true" />
<column name="name" type="VARCHAR" size="255" />
<column name="address" type="VARCHAR" size="255" />
etc...
<table name="lead_communities">
<column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true"/>
<column name="lead_id" type="INTEGER" />
<column name="community_id" type="INTEGER" />
<column name="created_date" type="DATE" size="4" />
<foreign-key foreignTable="community" refPhpName="Lead_Communities">
<reference local="community_id" foreign="id"/>
</foreign-key>
<foreign-key foreignTable="lead" refPhpName="Lead_Communities">
<reference local="lead_id" foreign="id"/>
</foreign-key>
</table>
<table name="lead">
<column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true"/>
<column name="salutation" type="VARCHAR" size="20" />
<column name="first_name" type="VARCHAR" size="255" defaultValue="" />
<column name="last_name" type="VARCHAR" size="255" defaultValue="" />
<column name="email" type="VARCHAR" size="255" defaultValue="" />
etc..
Here's how I select the lead from the database:
$lead = LeadQuery::create()->filterByEmail($enauk)->findOne();
So, what I hope to do is something like:
$lead->deleteLeadCommunities();
Well, the easiest way I can think of without any other context is simply doing a query on the join table with a delete() call:
$numDeleted = LeadCommunitiesQuery::create()
->filterByLead($lead)
->delete();
Just to be clear, there is no generated method like what you want (deleteLeadCommunities), but you could always write it for convenience, and replace $lead in my example code with $this. So inside Lead.php:
public function deleteLeadCommunities() {
return LeadCommunitiesQuery::create()
->filterByLead($this)
->delete();
}

PLINQO Primary key AND index problem

I've two tables, Profile and ProfileCategory
ProfileId INT IX
UserId UNIQUEIDENTIFIER PK (For one-to-one mapping with aspnet_membership)
CompanyName
Description
ProfileCategory
CategoryId
ProfileId
When I generate the code with PLINGO I get following errors
Operator '==' cannot be applied to operands of type 'int?' and 'System.Guid'
Operator '==' cannot be applied to operands of type 'int?' and 'System.Guid'
I dived into the generated code and the following..
[System.Diagnostics.DebuggerNonUserCode]
[System.CodeDom.Compiler.GeneratedCode("CodeSmith", "5.0.0.0")]
private void OnProfileList1Remove(Profile entity)
{
SendPropertyChanging(null);
var profileCategory = ProfileCategoryList.FirstOrDefault(c => c.CategoryId == CategoryId
&& c.ProfileId == entity.UserId);
ProfileCategoryList.Remove( profileCategory);
SendPropertyChanged(null);
}
So the generated code seems to want to compare the index and the primary key
I can manually alter the code but on regeneration it will be altered back.
Does anyone know why this is happening?
Thanks
Here is the profile snipet from the dbml
<Table Name="dbo.Profile" Member="Profile">
<Type Name="Profile">
<Column Name="UserId" Storage="_userId" Type="System.Guid" DbType="uniqueidentifier NOT NULL" IsPrimaryKey="true" CanBeNull="false" />
<Column Name="ProfileId" Storage="_profileId" Type="System.Int32" DbType="int NOT NULL IDENTITY" CanBeNull="false" />
<Column Name="CompanyName" Storage="_companyName" Type="System.String" DbType="nvarchar(250) NOT NULL" CanBeNull="false" />
<Column Name="Description" Storage="_description" Type="System.String" DbType="varchar(MAX)" CanBeNull="true" />
<Column Name="Services" Storage="_services" Type="System.Xml.Linq.XElement" DbType="xml" CanBeNull="true" UpdateCheck="Never" />
<Column Name="ContactDetails" Storage="_contactDetails" Type="System.Xml.Linq.XElement" DbType="xml" CanBeNull="true" UpdateCheck="Never" />
<Column Name="Attributes" Storage="_attributes" Type="System.Xml.Linq.XElement" DbType="xml" CanBeNull="true" UpdateCheck="Never" />
<Column Name="StateId" Storage="_stateId" Type="System.Int32" DbType="int NOT NULL" CanBeNull="false" />
<Column Name="Views" Storage="_views" Type="System.Int32" DbType="int NOT NULL" CanBeNull="false" />
<Association Name="User_Profile" Member="User" Storage="_user" ThisKey="UserId" Type="User" IsForeignKey="true" DeleteRule="CASCADE" />
<Association Name="Profile_ProfileAddress" Member="ProfileAddressList" Storage="_profileAddressList" OtherKey="UserId" Type="ProfileAddress" DeleteOnNull="false" />
<Association Name="Profile_Review" Member="ReviewList" Storage="_reviewList" ThisKey="ProfileId" OtherKey="ProfileId" Type="Review" DeleteOnNull="false" />
<Association Name="Profile_ProfileCategory" Member="ProfileCategoryList" Storage="_profileCategoryList" ThisKey="ProfileId" OtherKey="ProfileId" Type="ProfileCategory" />
</Type>
</Table>
<Table Name="dbo.ProfileCategory" Member="ProfileCategory">
<Type Name="ProfileCategory">
<Column Name="ProfileCategoryId" Storage="_profileCategoryId" Type="System.Int32" DbType="int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" />
<Column Name="ProfileId" Storage="_profileId" Type="System.Int32" DbType="int" CanBeNull="true" />
<Column Name="CategoryId" Storage="_categoryId" Type="System.Int32" DbType="int NOT NULL" CanBeNull="false" />
<Association Name="Category_ProfileCategory" Member="Category" Storage="_category" ThisKey="CategoryId" Type="Category" IsForeignKey="true" />
<Association Name="Profile_ProfileCategory" Member="Profile" Storage="_profile" ThisKey="ProfileId" OtherKey="ProfileId" Type="Profile" IsForeignKey="true" DeleteRule="CASCADE" />
</Type>
</Table>
Have you checked to make sure this wasn't already fixed in a nightly build of PLINQO? Could you please post the schema (or send to CodeSmith support) for these two tables.
Thanks
-Blake Niemyjski