Executing merge statement via C# SqlCommand not working

寵の児 提交于 2019-12-23 21:56:52

问题


I am making my first attempt at using a temp table and a MERGE statement to update a SQL table via a SqlCommand object in C#. The program I'm working on is designed to first export a very large set of records (upwards of 20k+) into an excel spreadsheet. The user then has the ability to do a search and replace for a specific value and update as many fields in as many records as they like.

What I'm trying to do is then take that spreadsheet, populate a DataTable with it, and then populate a temporary SQL table with the DataTable using SqlBulkCopy.

I then use a MERGE statement to update the rows if they still exist in the database.

However, the problem I'm having is a Unique Constraint I have on the ZipCodeTerritory table keeps being triggered giving me the following error message:

Cannot insert duplicate key row in object 'dbo.ZipCodeTerritory' with unique index 'UQ_ChannelStateEndDateZipCodeISNULL'. The duplicate key value is (9, CA , 94351 , 9999-12-31).

This leads me to believe that somehow either the UPDATE statement isn't being executed or I have somehow joined the tables incorrectly in the part of the statement using the ON keyword. The unique constraint is only triggered during INSERT statements or an UPDATE to the ChannelCode, StateCode, ZipCode or EndDate fields. I am doing a mass update to the IndDistrnId field and have thoroughly checked the spreadsheet.

Again, this is my first attempt at trying this technique so any help/suggestions would be greatly appreciated. Thanks

C#

private static string updateCommand = "UPDATE SET Target.ChannelCode = Source.ChannelCode, Target.DrmTerrDesc = Source.DrmTerrDesc, Target.IndDistrnId = Source.IndDistrnId," +
                                            "Target.StateCode = Source.StateCode, Target.ZipCode = Source.ZipCode, Target.EndDate = Source.EndDate, Target.EffectiveDate = Source.EffectiveDate," +
                                            "Target.LastUpdateId = Source.LastUpdateId, Target.LastUpdateDate = Source.LastUpdateDate, Target.ErrorCodes = Source.ErrorCodes," +
                                            "Target.Status = Source.Status ";

//Load updates into datatable
DataTable table = LoadData(updates);

//Script to create temp table
string tmpTable =   "CREATE TABLE [dbo].[ZipCodeTerritoryTemp]( " +
                    "[ChannelCode] [char](1) NOT NULL, " +
                    "[DrmTerrDesc] [nvarchar](30) NOT NULL, " +
                    "[IndDistrnId] [char](3) NULL, " +
                    "[StateCode] [char](3) NOT NULL, " +
                    "[ZipCode] [char](9) NULL, " +
                    "[EndDate] [date] NOT NULL, " +
                    "[EffectiveDate] [date] NOT NULL, " +
                    "[LastUpdateId] [char](8) NULL, " +
                    "[LastUpdateDate] [date] NULL, " +
                    "[Id] [int] IDENTITY(1,1) NOT NULL, " +
                    "[ErrorCodes] [varchar](255) NULL, " +
                    "[Status] [char](1) NULL, " +
                    "CONSTRAINT [PK_ZipCodeTerritoryTemp] PRIMARY KEY NONCLUSTERED  " +
                "( " +
                    "[Id] ASC " +
                ")WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY] " +
                ") ON [PRIMARY]";

using (SqlConnection connection = new SqlConnection(connString))
{
    connection.Open();

    //Create temp table
    SqlCommand cmd = new SqlCommand(tmpTable, connection);
    cmd.ExecuteNonQuery();

    try
    {

        using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connection))
        {
            //Write to temp table
            bulkCopy.DestinationTableName = "ZipCodeTerritoryTemp";
            bulkCopy.WriteToServer(table);

            //Merge changes in temp table with ZipCodeTerritory
            string mergeSql = "merge ZipCodeTerritory as Target " +
                                "using ZipCodeTerritoryTemp as Source " +
                                "on " +
                                "Target.Id = Source.Id " +
                                "when matched then " +
                                updateCommand + ";";

            cmd.CommandText = mergeSql;
            int results = cmd.ExecuteNonQuery();

            //Drop temp table
            cmd.CommandText = "DROP TABLE [dbo].[ZipCodeTerritoryTemp]";
            cmd.ExecuteNonQuery();
        }
    }
    catch (Exception)
    {
        throw;
    }
    finally
    {
        //Drop temp table
        SqlCommand final = new SqlCommand("DROP TABLE [dbo].[ZipCodeTerritoryTemp]", connection);
        final.ExecuteNonQuery();
    }
}

SQL

For readability's sake here's the MERGE statement as I wrote it in SQL Server Management Studio. I copied this into the C#. FYI - ran this statement in Management Studio and received the exact same error message.

MERGE INTO ZipCodeTerritory as Target
USING ZipCodeTerritoryTemp as Source
ON Target.Id = Source.Id

WHEN MATCHED THEN

UPDATE SET Target.ChannelCode = Source.ChannelCode, Target.DrmTerrDesc = Source.DrmTerrDesc, Target.IndDistrnId = Source.IndDistrnId,
    Target.StateCode = Source.StateCode, Target.ZipCode = Source.ZipCode, Target.EndDate = Source.EndDate, Target.EffectiveDate = Source.EffectiveDate,
    Target.LastUpdateId = Source.LastUpdateId, Target.LastUpdateDate = Source.LastUpdateDate, Target.ErrorCodes = Source.ErrorCodes,
    Target.Status = Source.Status;

回答1:


The issue wound up being the IDENTITY property being set on the Id field in the temp table. After removing this I was able to run the MERGE without error. Here's the temp table now:

//Script to create temp table
string tmpTable =   "CREATE TABLE [dbo].[ZipCodeTerritoryTemp]( " +
                    "[ChannelCode] [char](1) NOT NULL, " +
                    "[DrmTerrDesc] [nvarchar](30) NOT NULL, " +
                    "[IndDistrnId] [char](3) NULL, " +
                    "[StateCode] [char](3) NOT NULL, " +
                    "[ZipCode] [char](9) NULL, " +
                    "[EndDate] [date] NOT NULL, " +
                    "[EffectiveDate] [date] NOT NULL, " +
                    "[LastUpdateId] [char](8) NULL, " +
                    "[LastUpdateDate] [date] NULL, " +
                    "[Id] [int] NOT NULL, " +               //DO NOT GIVE THE PK OF THE TEMP TABLE AN IDENTITY(1,1,) PROPRETY
                    "[ErrorCodes] [varchar](255) NULL, " +
                    "[Status] [char](1) NULL, " +
                    "CONSTRAINT [PK_ZipCodeTerritoryTemp] PRIMARY KEY NONCLUSTERED  " +
                "( " +
                    "[Id] ASC " +
                ")WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY] " +
                ") ON [PRIMARY]";


来源:https://stackoverflow.com/questions/21172842/executing-merge-statement-via-c-sharp-sqlcommand-not-working

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!