Meilleure façon d'obtenir l'identité de la ligne insérée?
Quelle est la meilleure façon d'obtenir IDENTITY
de la rangée insérée?
je connais @@IDENTITY
et IDENT_CURRENT
et SCOPE_IDENTITY
mais je ne comprends pas le pour et le contre attachés à chacun.
est-ce que quelqu'un peut expliquer les différences et quand je devrais les utiliser?
11 réponses
-
@@IDENTITY
renvoie la dernière valeur d'identité générée pour n'importe quelle table de la session courante, dans tous les domaines. vous devez être prudent ici , car il est à travers les portées. Vous pouvez obtenir une valeur à partir d'un déclencheur, au lieu de votre déclaration actuelle. -
SCOPE_IDENTITY()
renvoie la dernière valeur d'identité générée pour n'importe quelle table session en cours et portée actuelle. Généralement ce que vous voulez utiliser . -
IDENT_CURRENT('tableName')
renvoie la dernière valeur d'identité générée pour une table spécifique dans n'importe quelle session et n'importe quelle portée. Cela vous permet de spécifier de quelle table vous voulez la valeur, dans le cas où les deux ci-dessus ne sont pas tout à fait ce dont vous avez besoin ( très rare ). Aussi, comme @ Guy Starbuck mentionné, "vous pouvez utiliser ceci si vous voulez obtenir la valeur D'identité courante pour une table dans laquelle vous n'avez pas inséré un enregistrement." -
la
OUTPUT
clause de la déclarationINSERT
vous permettra d'accéder à chaque ligne qui a été insérée via cette déclaration. Comme il est scoped à l'énoncé spécifique, il est plus simple que les autres fonctions ci-dessus. Cependant, c'est un peu plus verbeux (vous aurez besoin d'insérer dans une table variable/temp table et puis interrogation que) et il donne des résultats même dans un scénario d'erreur où l'énoncé est retranché. Cela dit, si votre requête utilise un plan d'exécution parallèle, il s'agit de la seule méthode garantie pour obtenir l'identité (à moins de désactiver le parallélisme). Cependant, il est exécuté avant déclencheurs et ne peut pas être utilisé pour retourner déclencheur généré valeur.
je crois que la méthode la plus sûre et la plus précise pour récupérer l'id inséré serait d'utiliser la clause de sortie.
par exemple (tiré de l'article suivant MSDN )
USE AdventureWorks2008R2;
GO
DECLARE @MyTableVar table( NewScrapReasonID smallint,
Name varchar(50),
ModifiedDate datetime);
INSERT Production.ScrapReason
OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
INTO @MyTableVar
VALUES (N'Operator error', GETDATE());
--Display the result set of the table variable.
SELECT NewScrapReasonID, Name, ModifiedDate FROM @MyTableVar;
--Display the result set of the table.
SELECT ScrapReasonID, Name, ModifiedDate
FROM Production.ScrapReason;
GO
je dis la même chose que les autres gars, donc tout le monde a raison, j'essaie juste de le rendre plus clair.
@@IDENTITY
renvoie l'id de la dernière chose qui a été insérée par la connexion de votre client à la base de données.
La plupart du temps, cela fonctionne très bien, mais parfois un déclencheur va et insérer une nouvelle ligne que vous ne connaissez pas, et vous obtiendrez L'ID de cette nouvelle ligne, au lieu de celui que vous voulez
SCOPE_IDENTITY()
résout ce problème. Il renvoie l'id de la dernière chose que vous avez insérée dans le code SQL que vous avez envoyé à la base de données. Si les déclencheurs vont et créent des lignes supplémentaires, ils ne causeront pas la mauvaise valeur pour être retournés. Hourra
IDENT_CURRENT
renvoie la dernière ID qui a été insérée par quelqu'un. Si une autre application arrive à insérer une autre ligne à un moment Non choisi, vous obtiendrez L'ID de cette ligne au lieu de votre.
si vous voulez jouer en toute sécurité, Utilisez toujours SCOPE_IDENTITY()
. Si vous vous en tenez à @@IDENTITY
et que quelqu'un décide d'ajouter un déclencheur plus tard, tout votre code se brisera.
le meilleur (lire: le plus sûr) moyen d'obtenir l'identité d'une ligne nouvellement insérée est en utilisant la output
clause:
create table TableWithIdentity
( IdentityColumnName int identity(1, 1) not null primary key,
... )
-- type of this table's column must match the type of the
-- identity column of the table you'll be inserting into
declare @IdentityOutput table ( ID int )
insert TableWithIdentity
( ... )
output inserted.IdentityColumnName into @IdentityOutput
values
( ... )
select @IdentityValue = (select ID from @IdentityOutput)
ajouter
SELECT CAST(scope_identity() AS int);
à la fin de votre instruction sql insert, puis
NewId = command.ExecuteScalar()
le récupérera.
@@ @ IDENTITY, SCOPE_IDENTITY et IDENT_CURRENT sont des fonctions similaires en ce qu'elles renvoient la dernière valeur insérée dans la colonne identité d'une table.
@@ @ IDENTITY et SCOPE_IDENTITY retourneront la dernière valeur d'identité générée dans n'importe quelle table de la session en cours. Cependant, SCOPE_IDENTITY renvoie la valeur uniquement dans la portée actuelle; @IDENTITY n'est pas limité à une portée.
IDENT_CURRENT n'est pas limitée par l'étendue et la session; elle est limitée à une table spécifiée. IDENT_CURRENT retourne la valeur d'identité générée pour une table spécifique dans n'importe quelle session et n'importe quelle portée. Pour en savoir plus, lisez IDENT_CURRENT.
- IDENT_CURRENT est une fonction qui prend une table comme argument.
- @@IDENTITY may return résultat confus lorsque vous avez un déclencheur sur la table
- SCOPE_IDENTITY est votre héros la plupart du temps.
@@IDENTITY est la dernière identité insérée en utilisant la connexion SQL actuelle. C'est une bonne valeur pour retourner d'une procédure stockée insert, où vous avez juste besoin de l'identité insérée pour votre nouvel enregistrement, et ne vous souciez pas si plus de lignes ont été ajoutées après.
SCOPE_IDENTITY est la dernière identité insérée en utilisant la connexion SQL actuelle, et dans la portée actuelle -- c'est-à-dire s'il y avait une deuxième identité inséré sur la base d'un déclencheur après votre insertion, il ne serait pas reflété dans SCOPE_IDENTITY, seulement l'insertion que vous avez effectuée. Franchement, je n'ai jamais eu une raison de l'utiliser.
IDENT_CURRENT(tablename) est la dernière identité insérée indépendamment de la connexion ou de la portée. Vous pouvez utiliser ceci si vous voulez obtenir la valeur D'identité courante pour une table dans laquelle vous n'avez pas inséré d'enregistrement.
lorsque vous utilisez Entity Framework, il utilise en interne la technique OUTPUT
pour retourner la valeur D'ID nouvellement insérée
DECLARE @generated_keys table([Id] uniqueidentifier)
INSERT INTO TurboEncabulators(StatorSlots)
OUTPUT inserted.TurboEncabulatorID INTO @generated_keys
VALUES('Malleable logarithmic casing');
SELECT t.[TurboEncabulatorID ]
FROM @generated_keys AS g
JOIN dbo.TurboEncabulators AS t
ON g.Id = t.TurboEncabulatorID
WHERE @@ROWCOUNT > 0
les résultats de sortie sont stockés dans une variable de table temporaire, joint de nouveau à la table, et retourner la valeur de ligne hors de la table.
Note: je n'ai aucune idée de la raison pour laquelle EF inner joindrait la table éphémère de nouveau à la table réelle (dans quelles circonstances les deux ne correspondraient pas).
Mais C'est ce que fait EF.
cette technique ( OUTPUT
) n'est disponible que sur SQL Server 2008 ou une version plus récente.
TOUJOURS utilisation scope_identity(), il n'y a JAMAIS un besoin de rien d'autre.
Je ne peux pas parler à d'autres versions de SQL Server, mais en 2012, outputting directement fonctionne très bien. Vous n'avez pas besoin de s'embêter avec une table temporaire.
INSERT INTO MyTable
OUTPUT INSERTED.ID
VALUES (...)
soit dit en passant, cette technique fonctionne également lors de l'insertion de lignes multiples.
INSERT INTO MyTable
OUTPUT INSERTED.ID
VALUES
(...),
(...),
(...)
sortie
ID
2
3
4
après votre Insertion, vous devez ajouter ceci. Et assurez-vous du nom de la table où les données sont insérées.Vous obtiendrez ligne actuelle pas de ligne affectée par votre instruction insert.
IDENT_CURRENT('tableName')