Est-il possible d'effectuer une instruction de mise à jour en sql, mais uniquement de mettre à jour si les mises à jour sont différentes?
par exemple
si dans la base de données, col1 = "hello"
update table1 set col1 = 'hello'
ne devrait pas effectuer tout type de mise à jour
toutefois, si
update table1 set col1 = "bye"
ceci devrait effectuer une mise à jour.
Cela est possible avec un déclencheur avant mise à jour. Dans ce déclencheur, vous pouvez comparer les anciennes aux nouvelles valeurs et annuler la mise à jour si elles ne diffèrent pas. Mais cela entraînera alors une erreur sur le site de l'appelant.
Je ne sais pas pourquoi vous voulez faire ça, mais voici plusieurs possibilités:
L'idée est de ne pas effectuer de mise à jour si une nouvelle valeur est la même que dans DB en ce moment
WHERE col1 != @newValue
(évidemment, il devrait aussi y avoir un champ Id
pour identifier une ligne)
WHERE Id = @Id AND col1 != @newValue
PS: à l'origine, vous ne voulez mettre à jour que si la valeur est 'bye', alors ajoutez simplement AND col1 = 'bye'
, mais je pense que c'est redondant, je suppose
Lors de la compilation et de l'exécution des requêtes, SQL Server ne prend pas le temps de déterminer si une instruction UPDATE va réellement modifier des valeurs ou non. Il effectue simplement les écritures comme prévu, même si cela n'est pas nécessaire.
Dans le scénario comme
update table1 set col1 = 'hello'
vous pensez peut-être que SQL ne fera rien, mais il le fera - il effectuera toutes les écritures nécessaires comme si vous aviez réellement modifié la valeur. Cela se produit à la fois pour la table physique (ou l'index cluster) ainsi que pour tous les index non cluster définis sur cette colonne. Cela provoque des écritures dans les tables/index physiques, le recalcul des index et les écritures du journal des transactions. Lorsque vous travaillez avec de grands ensembles de données, il y a d'énormes avantages en termes de performances à ne mettre à jour que les lignes qui recevront une modification.
Si nous voulons éviter la surcharge de ces écritures lorsque cela n'est pas nécessaire, nous devons trouver un moyen de vérifier la nécessité d'être mis à jour. Une façon de vérifier la nécessité d'une mise à jour serait d'ajouter quelque chose comme "où col <> 'bonjour'.
update table1 set col1 = 'hello' where col1 <> 'hello'
Mais cela ne fonctionnerait pas bien dans certains cas, par exemple si vous mettiez à jour plusieurs colonnes dans une table avec plusieurs lignes et que seul un petit sous-ensemble de ces lignes verrait en fait leurs valeurs modifiées. Cela est dû à la nécessité de filtrer ensuite toutes ces colonnes, et les prédicats de non-égalité ne sont généralement pas en mesure d'utiliser les recherches d'index, et la surcharge des écritures de table et d'index et des entrées du journal des transactions comme mentionné ci-dessus.
Mais il existe une bien meilleure alternative en utilisant une combinaison d'une clause EXISTS avec une clause EXCEPT. L'idée est de comparer les valeurs de la ligne de destination aux valeurs de la ligne source correspondante pour déterminer si une mise à jour est réellement nécessaire. Examinez la requête modifiée ci-dessous et examinez le filtre de requête supplémentaire commençant par EXISTS. Notez que dans la clause EXISTS, les instructions SELECT n'ont pas de clause FROM. Cette partie est particulièrement importante car cela n'ajoute qu'un balayage constant supplémentaire et une opération de filtrage dans le plan de requête (le coût des deux est trivial). Donc, vous vous retrouvez avec une méthode très légère pour déterminer si une MISE À JOUR est même nécessaire en premier lieu, en évitant une surcharge d'écriture inutile.
update table1 set col1 = 'hello'
/* AVOID NET ZERO CHANGES */
where exists
(
/* DESTINATION */
select table1.col1
except
/* SOURCE */
select col1 = 'hello'
)
Cela semble trop compliqué vs vérifier les mises à jour dans une simple clause WHERE pour le scénario simple dans la question d'origine lorsque vous mettez à jour une valeur pour toutes les lignes d'une table avec une valeur littérale. Cependant, cette technique fonctionne très bien si vous mettez à jour plusieurs colonnes dans une table et que la source de votre mise à jour est une autre requête et que vous souhaitez réduire les écritures et les entrées des journaux de transactions. Il fonctionne également mieux que de tester chaque champ avec <>.
Un exemple plus complet pourrait être
update table1
set col1 = 'hello',
col2 = 'hello',
col3 = 'hello'
/* Only update rows from CustomerId 100, 101, 102 & 103 */
where table1.CustomerId IN (100, 101, 102, 103)
/* AVOID NET ZERO CHANGES */
and exists
(
/* DESTINATION */
select table1.col1
table1.col2
table1.col3
except
/* SOURCE */
select z.col1,
z.col2,
z.col3
from #anytemptableorsubquery z
where z.CustomerId = table1.CustomerId
)
Si vous souhaitez modifier le champ en 'hello'
uniquement si c'est 'bye'
, utilisez ceci:
UPDATE table1
SET col1 = 'hello'
WHERE col1 = 'bye'
Si vous souhaitez mettre à jour uniquement s'il est différent de 'hello'
, utilisation:
UPDATE table1
SET col1 = 'hello'
WHERE col1 <> 'hello'
Y a-t-il une raison à cette étrange approche? Comme Daniel l'a commenté, il n'y a pas de gain spécial - sauf peut-être si vous avez des milliers de lignes avec col1='hello'
. Est-ce le cas?
CREATE OR REPLACE PROCEDURE stackoverflow([your_value] IN TYPE) AS
BEGIN
UPDATE [your_table] t
SET t.[your_collumn] = [your_value]
WHERE t.[your_collumn] != [your_value];
COMMIT;
EXCEPTION
[YOUR_EXCEPTION];
END stackoverflow;
Vous avez besoin d'une clé unique id
dans votre table (supposons que sa valeur est 1) pour faire quelque chose comme:
UPDATE table1 SET col1="hello" WHERE id=1 AND col1!="hello"
Ancienne question mais aucune des réponses n'adresse correctement les valeurs null
.
L'utilisation de <> ou! = Vous posera des problèmes lors de la comparaison des valeurs des différences s'il existe une valeur nulle potentielle dans la nouvelle ou l'ancienne valeur pour une mise à jour en toute sécurité uniquement en cas de modification, utilisez le is distinct from
opérateur à Postgres. En savoir plus ici
sans déclarer une variable ou similaire, il est difficile de se référer à la valeur codée en dur insérée. Si tel est votre objectif, vous devriez envisager la solution de Daniel Hilgarth. Normalement, vous aurez la valeur à portée de main. Dans ce cas, voici comment procéder.
declare @t table (col1 varchar(10))
insert @t values ('hello')
insert @t values ('bye')
declare @newvalueforallrows varchar(10)
set @newvalueforallrows = 'hello'
update @t set col1 = @newvalueforallrows
where col1 <> @newvalueforallrows
-- 1 row updated
Je pense que cela devrait faire l'affaire pour toi ...
create trigger [trigger_name] on [table_name]
for insert
AS declare @new_val datatype,@id int;
select @new_val = i.column_name from inserted i;
select @id = i.Id from inserted i;
update table_name set column_name = @new_val
where table_name.Id = @id and column_name != @new_val;