Je me demande s'il existe un moyen d'insérer un enregistrement dans une table uniquement si la table ne contient pas déjà cet enregistrement?
Y a-t-il une requête qui fera cela, ou aurai-je besoin d'une procédure stockée?
Je me demande s'il existe un moyen d'insérer un enregistrement dans une table uniquement si la table ne contient pas déjà cet enregistrement?
Y a-t-il une requête qui fera cela, ou aurai-je besoin d'une procédure stockée?
Vous ne dites pas quelle est la version de SQL Server. Si SQL Server 2008, vous pouvez utiliser de FUSION
NB: Il est d'usage d'utiliser de Fusion pour un Upsert qui est ce que j'ai pensé à l'origine, la question a été poser mais c'est valable sans l' WHEN MATCHED
clause et juste avec un WHEN NOT MATCHED
clause ne sorte de travail pour ce cas également. Exemple D'Utilisation.
CREATE TABLE #A(
[id] [int] NOT NULL PRIMARY KEY CLUSTERED,
[C] [varchar](200) NOT NULL)
MERGE #A AS target
USING (SELECT 3, 'C') AS source (id, C)
ON (target.id = source.id)
/*Uncomment for Upsert Semantics
WHEN MATCHED THEN
UPDATE SET C = source.C */
WHEN NOT MATCHED THEN
INSERT (id, C)
VALUES (source.id, source.C);
En termes de coûts d'exécution les deux l'air à peu près égales lorsque l'Insert est à faire...
Lien vers le plan des images de la première exécution
mais dans la deuxième manche quand il n'y a pas d'insérer à faire de Matthieu réponse semble plus faible coût. Je ne sais pas si il existe un moyen d'améliorer cela.
Lien vers le plan des images pour la deuxième manche
Script De Test
select *
into #testtable
from master.dbo.spt_values
CREATE UNIQUE CLUSTERED INDEX [ix] ON #testtable([type] ASC,[number] ASC,[name] ASC)
declare @name nvarchar(35)= 'zzz'
declare @number int = 50
declare @type nchar(3) = 'A'
declare @low int
declare @high int
declare @status int = 0;
MERGE #testtable AS target
USING (SELECT @name, @number, @type, @low, @high, @status) AS source (name, number, [type], low, high, [status])
ON (target.[type] = source.[type] AND target.[number] = source.[number] and target.[name] = source.[name] )
WHEN NOT MATCHED THEN
INSERT (name, number, [type], low, high, [status])
VALUES (source.name, source.number, source.[type], source.low, source.high, source.[status]);
set @name = 'yyy'
IF NOT EXISTS
(SELECT *
FROM #testtable
WHERE [type] = @type AND [number] = @number and name = @name)
BEGIN
INSERT INTO #testtable
(name, number, [type], low, high, [status])
VALUES (@name, @number, @type, @low, @high, @status);
END
En bref, vous avez besoin d'une table garantie pour vous fournir la possibilité de retourner une ligne:
Insert dbo.Table (Col1, Col2, Col3....
Select 'Value1', 'Value2', 'Value3',....
From Information_Schema.Tables
Where Table_Schema = 'dbo'
And Table_Name = 'Table'
And Not Exists (
Select 1
From dbo.Table
Where Col1 = 'Foo'
And Col2 = 'Bar'
And ....
)
J'ai également vu cette variation dans la nature:
Insert Table (Col1, Col2, Col3....
Select 'Value1', 'Value2', 'Value3'....
From (
Select 1 As Num
) As Z
Where Not Exists (
Select 1
From Table
Where Col1 = Foo
And Col2 = Bar
And ....
)
Je vote pour l'ajout d'un CONSTRAINT
. C'est le plus simple et le plus robuste de réponse. Je veux dire, en regardant comment compliqué autres réponses sont je dirais qu'ils sont beaucoup plus difficiles à obtenir le droit (et garder la droite).
Les inconvénients: [1] il n'est pas évident de lire le code que l'unicité est appliquée dans la base de données [2] le code client doit savoir pour intercepter une exception. En d'autres termes, le gars à venir après vous pourriez vous demander "comment cela fonctionne?"
À part de ça: j'ai utilisé à s'inquiéter de lancer/attraper l'exception a été un gain de performance, mais j'ai fait quelques tests (sur SQL Server 2005) et il n'était pas significative.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.