views:

83

answers:

3

Hi

I am using ms sql server 2005 and I want to do a mass update. I am thinking that I might be able to do it with sending an xml document to a stored procedure.

So I seen many examples on how to do it for insert

CREATE PROCEDURE [dbo].[spTEST_InsertXMLTEST_TEST](@UpdatedProdData XML)
AS 
   INSERT INTO 
      dbo.UserTable(CreateDate)
      SELECT
         @UpdatedProdData.value('(/ArrayOfUserTable/UserTable/CreateDate)[1]', 'DATETIME')

But I am not sure how it would look like for an update.

I am also unsure how do I pass in the xml through ado.net? Do I pass it as a string through a parameter or what?

I know sqlDataApater has a batch update method but I am using linq to sql. So I rather keep using it. So if this works I would be able to grab all records with linq to sql and have them as objects. Then manipulate the objects and use xml seralization.

Finally I could just use ado.net simple to send the xml to the server. This might be slower then the sqlDataAdapter but I am willing to take that hit if I can keep using objects.

Edit

Ok I have this so far

This is my XML

<?xml version="1.0" encoding="utf-16"?>
<ArrayOfUserTable xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
  <UserTable>
    <CreateDate>2011-05-21T11:04:55.0584669-07:00</CreateDate>
    <id>0</id>
    <AnotherField>false</AnotherField>
  </UserTable>
  <UserTable>
    <CreateDate>2015-05-21T11:04:55.061467-07:00</CreateDate>
    <id>0</id>
    <AnotherField>true</AnotherField>
  </UserTable>
</ArrayOfUserTable>

Two problems occurs with this the first one is

XML parsing: line 1, character 39, unable to switch the encoding

Second problem is with dates.

Conversion failed when converting datetime from character string.

Here is my C# code.

using (TestDataContext db = new TestDataContext())
{
   UserTable[] testRecords = new UserTable[2];
   for (int count = 0; count < 2; count++)
   {
      UserTable testRecord = new UserTable();

      if (count == 1)
      {
         testRecord.CreateDate = DateTime.Now.AddYears(5);
         testRecord.AnotherField = true;
      }
      else
      {
         testRecord.CreateDate = DateTime.Now.AddYears(1);
         testRecord.AnotherField = false;
      }

      testRecords[count] = testRecord;
  }

  StringBuilder sBuilder = new StringBuilder();
  System.IO.StringWriter sWriter = new System.IO.StringWriter(sBuilder);
  XmlSerializer serializer = new XmlSerializer(typeof(UserTable[]));
  serializer.Serialize(sWriter, testRecords);             

  using (SqlConnection con = new SqlConnection(connectionString))
  {
      string sprocName = "spTEST_UpdateTEST_TEST";

      using (SqlCommand cmd = new SqlCommand(sprocName, con))
      {
         cmd.CommandType = CommandType.StoredProcedure;

         cmd.CommandType = System.Data.CommandType.StoredProcedure;

         SqlParameter param1 = new SqlParameter("@UpdatedProdData", SqlDbType.VarChar, int.MaxValue);
         param1.Value = sBuilder.ToString();
         cmd.Parameters.Add(param1);

         con.Open();
         int result = cmd.ExecuteNonQuery();
         con.Close();
      }
   }
}

So to get around those 2 issues I just hand coded a small xml file that did not have the xml tag on top of it and only had MM/DD/YYYY for all dates to make that happy.

But it still does not work

USE [Test]
GO
/****** Object:  StoredProcedure [dbo].[spTEST_UpdateTEST_TEST]    Script Date: 05/21/2010 11:10:20 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[spTEST_UpdateTEST_TEST](@UpdatedProdData XML)
AS 
   UPDATE dbo.UserTable
   SET CreateDate =  @UpdatedProdData.value('(/ArrayOfUserTable/UserTable/CreateDate)[1]', 'DATETIME')
   WHERE AnotherField =  @UpdatedProdData.value('(/ArrayOfUserTable/UserTable/AnotherField)[1]', 'bit')

This does not even update any records. Also I still think this can only handle one record so I am not sure how to alter it to update many records.

+1  A: 

To call the stored proc from straight ADO.NET, you'd use the standard ADO.NET stuff as any programming book on .NET data access or ADO.NET tutorial (just Google for that!) will teach you:

using(SqlConnection con = new SqlConnection(your-connection-string-here))
{
     string sprocName = "spTEST_InsertXMLTEST_TEST";

     using(SqlCommand cmd = new SqlCommand(sprocName, con))
     {
         cmd.CommandType = CommandType.StoredProcedure;

         cmd.CommandType = System.Data.CommandType.StoredProcedure;

         SqlParameter param1 = new SqlParameter("@UpdatedProdData", SqlDbType.VarChar, int.MaxValue);
         param1.Value = YourXmlValueHere;
         cmd.Parameters.Add(param1);

         con.Open();
         int result = cmd.ExecuteNonQuery();
         con.Close();
     }    
}

Of course, you might want to wrap this into a try...catch block for exception handling and so forth - but that's basically the code you'd need to call that stored proc using straight ADO.NET.

UPDATE: in order to update your table from the XML, you should check out the .nodes() function in XQuery and write your update statement something like this:

UPDATE 
   dbo.UserTable
SET 
   CreateDate =  tbl.UPD.value('(CreateDate)[1]', 'DATETIME')
FROM
    @UpdatedProdData.nodes('/ArrayOfUserTable/UserTable') AS tbl(UPD)
WHERE 
    AnotherField =  tbl.UPD.value('(AnotherField)[1]', 'bit')

Basically, you're shredding your XML into a "virtual" table called tbl(UPD) - each entry of an <UserTable> tag now is a "row" in that virtual table (thus you can handle many rows), and you grab data from that virtual row to update your base table.

For a really good introduction to SQL-XML XQuery in SQL Server 2005 and up, check out this article on 15 Seconds - it's helped me tremendously to get a grasp on what is possible with XQuery, and how to do it in SQL Server's XQuery implementation.

marc_s
How would the stored procedure look like. Would it be similar to the insert where you do the XPath on it?
chobo2
@chobo2: yes, this code is intended to call that stored proc you've been using all throughout your last string of questions - nothing changes there.
marc_s
Well I am wondering more with the update in the stored procedure. Do I just change it to "Update" then with the "Set" part I just use the xpath(like '(/ArrayOfUserTable/UserTable/CreateDate)[1]')
chobo2
Ok I updated it with that I have now. It is still not working.
chobo2
@chobo2: added an update to my answer for your UPDATE scenario.
marc_s
I will check that out and play with your example. Do you know why I though I would be getting those 2 other errors?
chobo2
Ok I made my changes to my sp and tried it and it works on my small 2 row update. I then tired to move it to my real copy and I get this error.The query has been canceled because the estimated cost of this query (575) exceeds the configured threshold of 300. Contact the system administrator.I am not sure what it means but I am guessing I am taking too much resources to complete this update task. So if that is the case I am not sure if I can do this as I am sure my hosting company will not raise this limit and if they do I probably would have to pay for it.
chobo2
A: 

I think you could get the XML into temp table and then use it into update part of the stored procedure. Not sure if that answers the questions though!

Atul
I am not sure how that would work. So not sure if it would answer my question.
chobo2
A: 

for that pass the XMLDOC1 as your parameter in procedure. in you .net code write dataset.Writexml and that will give to string variable and pass that string to the procedure as parameter. below is the example of how you get data in procedure. @XMLDoc1 as text

DECLARE @idoc1 as int

EXEC sp_xml_preparedocument @idoc1 OUTPUT, @XMLDoc1

Select * into #TableName
FROM OPENXML(@idoc1,'/NewDataSet/Tablename',2)
WITH (structure of Table like below) (PrefDetailID int
,PrefID int )

--select * from #TableName

EXEC sp_xml_removedocument @idoc1
now you got all your data in the #TableName and manipulte as you like in procedure do any thing insert or update or check below link this my own blog http://sqlmca.wordpress.com/2009/07/29/how-to-get-data-from-dataset-into-sqlserver-table-by-using-openxml-method/

KuldipMCA
I been told you should not use OPENXML if your using sql server 2005.
chobo2
Using OpenXML and all that messy stuff is totally unnecessary with SQL Server 2005 and up - it's deprecated, check out the new XQuery stuff
marc_s