我第一次尝试使用临时表和MERGE
语句通过C#中的SqlCommand
对象更新SQL表。我正在研究的程序旨在首先将一组非常大的记录(超过20k +)导出到Excel电子表格中。然后,用户能够搜索并替换特定值,并在他们喜欢的记录中更新尽可能多的字段。
然后我要尝试的是获取该电子表格,用它填充DataTable
,然后使用DataTable
使用SqlBulkCopy
填充临时SQL表。
然后我使用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
为了便于阅读,这里是我在SQL Server Management Studio中编写的MERGE
语句。我将其复制到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;
答案 0 :(得分:2)
问题结果是临时表中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]";