Inserting into SQL using an OpenXml - c#

Hi I am trying to insert data into an SQL Server Database using an XML file which has some data as follows.I was able to do the attribute mapping in OPENXML.If i try to pass the XML as elements instead of attributes i get an error regarding the null insertion.
Following is my XML FILE (containg attributes)
<NewDataSet>
<SampleDataTable id="20" Name="as" Address="aaa" Email="aa" Mobile="123" />
</NewDataSet>
I am successful using the above format.If i use the below format i face errors
<Customer>
<Id>20</Id>
<Name>Cn</Name>
<Address>Pa</Address>
<Email>bnso#gmail.com</Email>
<Mobile>12345513213</Mobile>
</Customer>
This is my openXML in SQL
insert into #tempTable
select * from openxml (#xmlHandle,'ROOT/Customer/',1)
with (Cust_id int '#id',
Customer_Name varchar(30) '#Name',
Address varchar(30) '#Address',
Email_id varchar(30) '#Email',
Mobile_no bigint '#Mobile'
)
Insert into Test.dbo.tblCustomers (Cust_id,Customer_Name,Address,Email,Mobile_No) (select * from #tempTable)
please help

It's because you're trying to fetch data as attributes, but int your xml data is inside elements. Try this:
insert into #tempTable
select *
from openxml (#xmlHandle,'ROOT/Customer/',1)
with (Cust_id int '#id',
Customer_Name varchar(30) 'Name[1]',
Address varchar(30) 'Address[1]',
Email_id varchar(30) 'Email[1]',
Mobile_no bigint 'Mobile[1]'
)
Or you can do this without openxml:
select
t.c.value('Name[1]', 'varchar(30)') as Name,
t.c.value('Address[1]', 'varchar(30)') as Address,
t.c.value('Email[1]', 'varchar(30)') as Email,
t.c.value('Mobile[1]', 'bigint') as Mobile
from #Data.nodes('Customer') as t(c)
sql fiddle demo

The problem is "element value" vs "element attribute".
This page has good examples of both:
http://technet.microsoft.com/en-us/library/ms187897%28v=sql.90%29.aspx
<Customer>
<CustomerID>LILAS</CustomerID>
<ContactName>Carlos Gonzlez</ContactName>
<Order OrderID="10283" CustomerID="LILAS" EmployeeID="3" OrderDate="1996-08-16T00:00:00">
<OrderDetail ProductID="72" Quantity="3"/>
</Order>
</Customer>
</ROOT>'
-- Create an internal representation of the XML document.
EXEC sp_xml_preparedocument #XmlDocumentHandle OUTPUT, #XmlDocument
-- Execute a SELECT statement using OPENXML rowset provider.
SELECT *
FROM OPENXML (#XmlDocumentHandle, '/ROOT/Customer',2)
WITH (CustomerID varchar(10),
ContactName varchar(20))
EXEC sp_xml_removedocument #XmlDocumentHandle

Related

update and insert query for split name

can anyone please help me right the following stored procedure of split name in first and last name in stored procedure in SQL for update and insert query.
Create[dbo].[storedprocedure]
SELECT LEFT(#FullName, CHARINDEX(',', #FullName) - 1) AS [FirstName],
RIGHT(#FullName, CHARINDEX(',', REVERSE(#FullName)) - 1) AS [LastName]
From table name
Thanks in advance
If I've understood your request you could create a type to use as list parameter for the procedure
CREATE TYPE [dbo].[FullNamesList] AS TABLE(
[FullName] varchar(20) NULL
);
and after this, you can create this procedure to insert splitter name the table you prefer (my FirstLastNameTable)
CREATE PROCEDURE [dbo].[storedprocedure]
#groupFullNames FullNamesList READONLY
AS
BEGIN
INSERT INTO FirstLastNameTable(FirstName, LastName)
SELECT LEFT(G.FullName, CHARINDEX(',', G.FullName) - 1) AS [FirstName],
RIGHT(G.FullName, CHARINDEX(',', REVERSE(G.FullName)) - 1) AS [LastName]
FROM #groupFullNames G
END

Return string via stored procedure using C#

I have a table which has a column that is being auto-generated based on other columns in the table. I am attempting to insert data into the table using a stored procedure and then return the auto-generate column. In the stored procedure below, #Num represents the auto-generated column.
The approach I am taking here works with regard to inserting the data into the database. What isn't working is returning #Num from the Insert stored procedure. Is what I am trying to do possible. If so what am I doing wrong? If not, is there an alternative method to accomplish this?
This is my C#. When I run this, returnValue comes back null.
internal static bool InsertApplication(Something something)
{
object returnValue;
string sql = "usp_InsertSproc";
returnValue = DatabaseFactory.CreateDatabase("ConnectionString").ExecuteScalar(sql, new Object[] { something.First_Name, something.Last_Name });
//I'd like to be able to access the #Num value from the Sproc here
}
This is my stored procedure:
ALTER PROCEDURE [dbo].[usp_InsertSproc]
(
#First_Name varchar(50),
#Last_Name varchar(50),
#Num Varchar(500) Output
)
AS
SET NOCOUNT OFF;
INSERT INTO [Table] ([First_Name], [Last_Name])
VALUES (#First_Name, #Last_Name, )
Return #Num
This is what my table looks like.
CREATE TABLE [Table]
(
[First_Name] VARCHAR(50),
[Last_Name] VARCHAR(50),
[Num] AS ([dbo].[SetCMP]([Num]))
)
I'm assuming your table looks something like this:
CREATE TABLE [Table]
(
[First_Name] VARCHAR(50),
[Last_Name] VARCHAR(50),
[Num] AS [First_Name] + [Last_Name] + '!'
)
Your C# should be fine. Change your stored procedure to something like:
ALTER PROCEDURE [dbo].[usp_InsertSproc]
#First_Name VARCHAR(50),
#Last_Name VARCHAR(50)
AS
SET NOCOUNT OFF;
INSERT INTO [Table] ([First_Name], [Last_Name])
OUTPUT inserted.[Num]
VALUES (#First_Name, #Last_Name)
GO
EXEC [dbo].[usp_InsertSproc]
#First_Name = 'Tom',
#Last_Name = 'Hunter'

Update rows in Database using XML data

This is the first time I am using XML to insert data into a table.I am saving the data from the front end(all the Datagridview rows) into an xml file and sending it to database to insert into table SD_ShippingDetails.Below is the Query for reading the XML data and saving data.As you can see from the Query I am deleting the related ShippingID details and inserting again.(DELETE FROM SD_ShippingDetails WHERE ShippingID=#ShippingID).Can we update already existing rows in the SD_ShippingDetails by getting the data from XML.If Yes,Please help me with the query.
CREATE PROCEDURE SD_Insert_ShippingDetails
#PBMXML as varchar(Max),
#ShippingID as INT
AS
BEGIn
declare #i int
exec sp_xml_preparedocument #i output,#PBMXML
DELETE FROM SD_ShippingDetails WHERE ShippingID=#ShippingID
INSERT INTO SD_ShippingDetails(ShippingID,Weight,Height,TotalBoxes,Price)
SELECT ShippingID,Weight,Height,TotalBoxes,Price FROM OPENXML(#i,'Root/ShippingBox',2)
WITH (
ShippingID int,Weight varchar(20),Height varchar(20),TotalBoxes varchar(20),Price numeric(18,2))
exec sp_xml_removedocument #i
END
Thanks.
You are on SQL Server 2005 so you can use the XML datatype instead of openxml so this answer uses that instead. Using the XML datatype is not necessary for the solution. You can rewrite using openxml if you want to.
You specified in a comments that there is an ID identity field in SD_ShippingDetails (I assume that is the primary key) but you also said that the combination of ShippingID and Weight is unique. That leaves us with a table structure that looks like this.
create table dbo.SD_ShippingDetails
(
ID int identity primary key,
ShippingID int not null,
Weight varchar(20) not null,
Height varchar(20),
TotalBoxes varchar(20),
Price numeric(18,2),
unique (ShippingID, Weight)
);
The stored procedure first needs to update all rows that already exist in SD_ShippingDetails and after that it needs to insert the rows that are missing.
create procedure dbo.SD_Insert_ShippingDetails
#PBMXML as xml
as
update dbo.SD_ShippingDetails
set Height = T.N.value('(Height/text())[1]', 'varchar(20)'),
TotalBoxes = T.N.value('(TotalBoxes/text())[1]', 'varchar(20)'),
Price = T.N.value('(Price/text())[1]', 'numeric(18,2)')
from #PBMXML.nodes('Root/ShippingBox') as T(N)
where ShippingID = T.N.value('(ShippingID/text())[1]', 'int') and
Weight = T.N.value('(Weight/text())[1]', 'varchar(20)');
insert into dbo.SD_ShippingDetails(ShippingID, Weight, Height, TotalBoxes, Price)
select T.N.value('(ShippingID/text())[1]', 'int'),
T.N.value('(Weight/text())[1]', 'varchar(20)'),
T.N.value('(Height/text())[1]', 'varchar(20)'),
T.N.value('(TotalBoxes/text())[1]', 'varchar(20)'),
T.N.value('(Price/text())[1]', 'numeric(18,2)')
from #PBMXML.nodes('Root/ShippingBox') as T(N)
where not exists (
select *
from dbo.SD_ShippingDetails
where ShippingID = T.N.value('(ShippingID/text())[1]', 'int') and
Weight = T.N.value('(Weight/text())[1]', 'varchar(20)')
);
SQL Fiddle
If you have Sql Server 2005, then placing the values in #temp or #variables tables is best.
With 2008 and up, you could piggy back on the MERGE functionality.
http://msdn.microsoft.com/en-us/library/bb522522(v=sql.105).aspx
Here is a good link for xml shredding. Note, you are using the older version of OPENXML. That was a more Sql Server 2000 command. Check Plamen's blog below for 2005 and above syntax.
http://pratchev.blogspot.com/2007/06/shredding-xml-in-sql-server-2005.html
I would populate your XML into a variable table and then use an Update Statement and an Insert with a Not Exists.
If you had SQL 2008 you could replace your delete and insert statements with this...
MERGE SD_ShippingDetails AS Target
USING (SELECT ShippingID,
Weight,
Height,
TotalBoxes,
Price
FROM OPENXML(#i,'Root/ShippingBox',2)
WITH (ShippingID int,
Weight varchar(20),
Height varchar(20),
TotalBoxes varchar(20),
Price numeric(18,2)) ) AS source (ShippingID,Weight,Height,TotalBoxes,Price)
ON (target.ShippingID = source.ShippingID)
WHEN MATCHED THEN
UPDATE SET Weight = source.Weight,
Height = source.Height,
TotalBoxes = source.TotalBoxes,
Price = source.Price
WHEN NOT MATCHED THEN
INSERT (ShippingID,Weight,Height,TotalBoxes,Price)
VALUES (source.ShippingID,source.Weight,source.Height,source.TotalBoxes,source.Price);

XML to SQL SERVER record insertion

I having XMl file I am Reading All the Xml using this code . But mean while I want to insert XML records to sql table,Whatever I have Read. I did not Find any Solution for that .XMl consists No of rows and how can i insert in Proper way .
if (File.Exists(xmlpath))
{
try
{
XDocument xmlDoc = XDocument.Load(xmlpath);
var vrresult = from a in xmlDoc.XPathSelectElements("/Parts/Part")
select new
{
S = a.Element("Section").Value,
M = a.Element("Mark").Value,
Q = a.Element("Qty").Value,
W = a.Element("Weight").Value,
RD = a.Element("databaseUpdateMark").Value
};
GridView1.DataSource = vrresult;
GridView1.DataBind();
}
catch (Exception ex)
{
Lbmsg.Text = ex.Message;
}
finally
{
}
}
here is one example how to use OPENXML function
Bulk Insertion of Data Using C# DataTable and SQL server OpenXML function
Make use of function : OPENXML (Transact-SQL) which is avialble in sql server allows you to insert data in server....
also read : Use OPENXML to insert values from a string of XML
Example :
--Use OPENXML to pull records from an XML string and insert them into a database
DECLARE #idoc int
DECLARE #doc varchar (1000)
--XML document
SET #doc ='
<ROOT>
<Employee>
<FirstName>Tom</FirstName>
<LastName>Jones</LastName>
</Employee>
<Employee>
<FirstName>Gus</FirstName>
<LastName>Johnson</LastName>
</Employee>
</ROOT>'
--Create an internal representation of the XML document
--the idoc variable is set as the document handler, so we can refer to it later
EXEC sp_xml_preparedocument #idoc OUTPUT, #doc
-- Use the OPENXML rowset provider with an Insert
-- #idoc lets us know which internal representation of an xml doc to use
-- '/ROOT/Employee' shows us which node in the xml tree to work on
-- the 2 denotes we want to use elemenet centric mapping for the values, as oppsed to attributes or a combination of both
-- in the 'With' we specify how the output rowset will look
INSERT INTO Employees (FirstName, LastName)
SELECT *
FROM OPENXML (#idoc, '/ROOT/Employee',2)
WITH (FirstName varchar(10),
LastName varchar(20)
)
-- Clear the XML document from memory
EXEC sp_xml_removedocument #idoc

Upsert on SQL Server table from XML

I'm attempting to create a small console app in C# to perform inserts on a table of Products (ITEMS) in SQL Server 2008 according to the contents of an XML file in the FASTEST way possible. I already have an .XSD file that contains the proper mappings to the SQL table (which may not be necessary with the approach outlined below).
Here's a high-level of my approach:
Read the XML, using it to create a table.
Perform a MERGE against the ITEMS table using the table created from the XML file.
2a. If the item exists, update it.
2b. If the item does not exist, insert it.
Create a log of only the records inserted in XML.
Consider the following ITEMS table and XML file:
ITEMS
Item_Id Name Price
1 Coke 5.00
2 Pepsi 3.00
3 Sprite 2.00
ITEMS.XML
<?xml version="1.0" encoding="ISO-8859-1"?>
<Item>
<Id>5</Id>
<Name>Mountain Dew</Name>
<Price>4.50</Price>
</Item>
<Item>
<Id>3</Id>
<Name>Sprite Zero</Name>
<Price>1.75</Price>
</Item>
After the import, the ITEMS table should look like:
ITEMS
Item_Id Name Price
1 Coke 5.00
2 Pepsi 3.00
3 Sprite Zero 1.75
5 Mountain Dew 4.50
Once that's done, I also need to generate an XML formatted log file that contains the "new" record that was inserted into the table (ITEMS_LOG.XML):
ITEMS_LOG.XML
<?xml version="1.0" encoding="ISO-8859-1"?>
<Item>
<Id>5</Id>
<Name>Mountain Dew</Name>
<Price>4.50</Price>
</Item>
I have tried implementing this using SQLXMLBulkLoad, but unfortunately it does not provide the logging that I need, nor does it permit me to access any of the messages returned from SQL Server (i.e. what's been inserted/updated). Although I have an intermediate level of SQL expertise, I am fairly new to working with XML, especially in this context. Any help/guidance would be greatly appreciated!
You can use merge with output to a table variable and then query the table variable to build the log XML.
Put it in a stored procedure where you have the item XML as an in parameter and the log XML as an out parameter.
create procedure AddItemXML
#ItemsXML xml,
#ItemsLogXML xml out
as
declare #Changes table
(
Item_Id int,
Name nvarchar(20),
Price money,
Action nvarchar(10)
);
merge Items as T
using
(
select T.N.value('Id[1]', 'int') as Item_Id,
T.N.value('Name[1]', 'varchar(20)') as Name,
T.N.value('Price[1]', 'money') as Price
from #ItemsXML.nodes('/Item') T(N)
) as S
on T.Item_Id = S.Item_Id
when matched then
update set Name = S.Name, Price = S.Price
when not matched then
insert (Item_Id, Name, Price) values (S.Item_Id, S.Name, S.Price)
output inserted.Item_Id,
inserted.Name,
inserted.Price,
$action
into #Changes;
set #ItemsLogXML =
(
select Item_Id as ID,
Name,
Price
from #Changes
where Action = 'INSERT'
for xml path('Item'), type
);
Working sample on SE-Data
Hope this helps you, What I did was to create a stored procedure as below. Basically the stored procedure takes xml values and checks the flags which are passed from code and determines if it is insert or update:
DECLARE #xml xml
SET #xml = #xmlCredentials
SELECT
item.value('#Id', 'int') As ID,
item.value('#AgentID', 'int') As AgentID,
item.value('#Username', 'varchar (50)') As Username,
item.value('#Password', 'varchar (50)') As [Password],
item.value('#IsDirty', 'bit') As IsDirty,
item.value('#IsDeleted', 'bit') As IsDeleted
INTO #tmp
FROM #xml.nodes('Credentials/Credential') x(item)
BEGIN TRY
BEGIN TRAN
INSERT INTO Credentials (AgentID, Username, [Password])
SELECT
AgentID, Username, [Password]
FROM
#tmp
WHERE
ID = 0 AND IsDirty = 1
UPDATE c
SET c.[AgentID] = t.AgentID,
c.[Username] = t.Username,
c.[Password] = t.[Password]
FROM
[dbo].[Credentials] c
JOIN
#tmp t ON t.Id = c.ID
WHERE
t.IsDirty = 1 AND t.IsDeleted = 0
DELETE FROM [dbo].[Credentials]
FROM [dbo].[Credentials] c
JOIN #tmp t ON t.Id = c.ID
WHERE
t.IsDirty = 1 AND t.IsDeleted = 1
COMMIT TRAN
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRAN
DECLARE #errorMSG varchar(4000)
DECLARE #errorSeverity int
DECLARE #errorState int
SET #errorMSG = ERROR_MESSAGE()
SET #errorSeverity = ERROR_SEVERITY()
SET #errorState = ERROR_STATE()
RAISERROR (#errorMSG,
#errorSeverity, #errorState);
END CATCH
SELECT [ID], [AgentID], [Username], [Password]
FROM [dbo].[Credentials]
In code behind I have my xml and pass the xml as parameter to the stored procedure:
// read xml and assign it to string variable
string xml = readxml();
try
{
string command = "EXEC SaveCredentails '" + xml + "'";
}
catch(Exception e)
{
}
I would use a staging table to import the xml into a SQL Server table. Add an extra column to indicate the action (insert or update). Then use regular sql to perform upserts as usual. You can then use the staging table to generate the XML logging you need (reading the action column to determine if it was an insert or update).

Categories

Resources