Выполнение оператора слияния через C# SqlCommand не работает
Я делаю свою первую попытку использовать временную таблицу и MERGE
заявление, чтобы обновить таблицу SQL через SqlCommand
объект в C#. Программа, над которой я работаю, предназначена для первого экспорта очень большого набора записей (более 20 000+) в таблицу Excel. Затем пользователь получает возможность выполнять поиск и замену определенного значения и обновлять столько полей в любом количестве записей, сколько ему нужно.
То, что я пытаюсь сделать, это взять эту таблицу, заполнить DataTable
с этим, а затем заполните временную таблицу SQL с DataTable
с помощью SqlBulkCopy
,
Затем я использую MERGE
оператор для обновления строк, если они все еще существуют в базе данных.
Однако проблема, с которой я столкнулся, заключается в том, что у меня есть ZipCodeTerritory
таблица продолжает работать, выдавая мне следующее сообщение об ошибке:
Невозможно вставить повторяющуюся строку ключа в объект "dbo.ZipCodeTerritory" с уникальным индексом "UQ_ChannelStateEndDateZipCodeISNULL". Дубликат значения ключа (9, CA, 94351, 9999-12-31).
Это приводит меня к мысли, что каким-то образом UPDATE
оператор не выполняется или я как-то неправильно соединил таблицы в части оператора, используя ON
ключевое слово. Уникальное ограничение срабатывает только во время INSERT
заявления или UPDATE
к ChannelCode
, StateCode
, ZipCode
или же EndDate
поля. Я делаю массовое обновление IndDistrnId
поле и тщательно проверили электронную таблицу.
Опять же, это моя первая попытка попробовать эту технику, поэтому любая помощь / предложения будут с благодарностью. Спасибо
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
Для удобства чтения вот MERGE
заявление, как я написал это в SQL Server Management Studio. Я скопировал это в C#. К вашему сведению - запустил этот оператор в Management Studio и получил точно такое же сообщение об ошибке.
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 ответ
Проблема оказалась в том, что IDENTITY
свойство устанавливается на Id
поле во временной таблице. После удаления этого я смог запустить MERGE
без ошибок. Вот временная таблица сейчас:
//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]";