Je tente d'abord d'utiliser une table temporaire et une instruction MERGE
pour mettre à jour une table SQL via un object SqlCommand
en C #. Le programme sur lequel je travaille est conçu pour exporter d'abord un très grand nombre d'loggings (plus de 20k +) dans une feuille de calcul Excel. L'user a alors la possibilité de faire une search et de replace pour une valeur spécifique et de mettre à jour autant de champs dans autant d'loggings qu'ils le souhaitent.
Ce que j'essaie de faire est alors prendre cette feuille de calcul, remplir un DataTable
avec elle, puis remplir une table SQL temporaire avec le DataTable
utilisant SqlBulkCopy
.
J'utilise ensuite une instruction MERGE
pour mettre à jour les lignes si elles existent encore dans la database.
Cependant, le problème que j'ai est une contrainte unique que j'ai sur la table ZipCodeTerritory
continue à être déclenchée en me donnant le message d'erreur suivant:
Impossible d'insert une ligne de key en double dans l'object 'dbo.ZipCodeTerritory' avec l'index unique 'UQ_ChannelStateEndDateZipCodeISNULL'. La valeur de la key en double est (9, CA, 94351, 9999-12-31).
Cela m'amène à croire que, d'une manière ou d'une autre, l'instruction UPDATE
n'est pas en cours d'exécution ou que j'ai joint les tables de manière incorrecte dans la partie de l'instruction en utilisant le mot key ON
. La contrainte unique est uniquement déclenchée pendant les instructions INSERT
ou UPDATE
dans les StateCode
ChannelCode
, StateCode
, StateCode
ou EndDate
. Je fais une mise à jour de masse sur le champ IndDistrnId
et j'ai soigneusement vérifié la feuille de calcul.
Encore une fois, c'est ma première tentative d'essayer cette technique, donc toute aide / suggestion serait grandement appréciée. Merci
C #
private static ssortingng 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 ssortingng 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(connSsortingng)) { 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 ssortingng 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
Pour des raisons de lisibilité, voici l'instruction MERGE
telle que je l'ai écrite dans SQL Server Management Studio. J'ai copié ceci dans le C #. FYI – a couru cette déclaration dans Management Studio et a reçu exactement le même message d'erreur.
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;
Le problème a fini par être la propriété IDENTITY
définie dans le champ Id
de la table temporaire. Après avoir enlevé cela, j'ai pu lancer le MERGE
sans erreur. Voici la table temporaire maintenant:
//Script to create temp table ssortingng 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]";