web-dev-qa-db-fra.com

Comment insérer des valeurs dans deux tables avec une relation de clé étrangère?

J'ai créé deux tables:

  • Table tblStaff avec colonnes id (clé primaire, incrémentation automatique), name, age, address

  • Table tblRoleOfStaff avec colonnes id (clé primaire, incrémentation automatique), StaffId (clé étrangère vers tblStaff), RoleId

J'ai la forme pour créer de nouveaux employés avec un rôle existant. Échantillon de données à insérer:

(name, age, address, roleId) = ('my name',20,'San Jose', 1)

Je veux écrire une procédure stockée dans SQL Server 2014 pour insérer un nouveau personnel dans tblStaff et insérer un nouvel enregistrement dans tbleRoleOfStaff avec staffId que je viens d'insérer.

Que devrais-je faire?

Je suis vraiment désolé si ma question fait double emploi avec d'autres. Je suis plus frais en SQL. Merci pour toute aide.

9
Ca Pham Van

Utilisez SCOPE_IDENTITY () seconde insertion dans tblRoleOfStuff à la place de StaffId. Comme:

insert into tblStaff values
(@name, @age, @address)

insert into tblRoleOfStuff values
(scope_identity(), @roleid)

[~ # ~] modifier [~ # ~]

Il y a trop de commentaires sur cette réponse, donc je veux donner une explication.

Si OP garantit qu'il n'utilisera aucun déclencheur, il pourra utiliser @@IDENTITY (Mauvaise pratique), cela suffit à ses besoins, mais la meilleure pratique consiste à utiliser SCOPE_IDENTITY().

SCOPE_IDENTITY (), comme @@ IDENTITY, renverra la dernière valeur d'identité créée dans la session en cours, mais elle la limitera également à votre portée actuelle. En d'autres termes, il renverra la dernière valeur d'identité que vous avez créée explicitement, plutôt que toute identité créée par un déclencheur ou une fonction définie par l'utilisateur.

SCOPE_IDENTITY() garantira que vous obtenez l'identité de l'opération en cours, et non d'une autre connexion ou de la dernière traitée.

Pourquoi pas IDENT_CURRENT? Car

IDENT_CURRENT n'est pas limité par la portée et la session; il est limité à une table spécifiée. IDENT_CURRENT renvoie la valeur d'identité générée pour une table spécifique dans n'importe quelle session et n'importe quelle étendue.

Donc, vous faites prendre la dernière portée mais pas la plus récente. Oui, OP peut aussi l'utiliser, mais c'est une mauvaise pratique dans cette situation (comme utiliser seulement @@IDENTITY)

L'utilisation de OUTPUT est en effet une bonne pratique, mais trop compliquée pour une seule identité. Si OP doit traiter plus d'une ligne à la fois - oui, il a besoin de OUTPUT.

12
gofr1

Parce qu'il semble que vous discutiez d'une ligne à la fois, certaines personnes peuvent vous dire d'utiliser un système tel que @@IDENTITY ou certains des autres, mais pour garantir avec plus de certitude, je recommande la clause OUTPUT de l'instruction d'insertion. La bonne chose à propos de cette méthode est qu'elle peut facilement être adaptée pour gérer plus d'une ligne à la fois.

DECLARE @Output AS TABLE (StaffId INT)

INSERT INTO tblStaff (name, age, address)
OUTPUT inserted.Id INTO @Output (StaffId)
VALUES (@name, @age, @address)

DECLARE @StaffId INT
SELECT @StaffId = StaffId FROM @Output

INSERT INTO tblRoleOfStaff (StaffId, RoleId)
VALUES (@StaffId,@RoleId)

Raisons de ne pas utiliser @@IDENTITY au cas où une autre opération liée à la vôtre serait effectuée. Par exemple. un déclencheur insère une autre ligne dans une autre table ou met à jour un autre enregistrement dans votre base de données., SCOPE_IDENTITY a un déficit similaire lorsqu'un déclencheur modifie la même table. IDENT_CURRENT a un court terme aussi. Faites une recherche sur Internet pour en savoir plus, il y a des tonnes d'excellentes ressources à ce sujet.

3
Matt

Vous pouvez utiliser output à partir de votre première instruction d'insertion.

declare @tmp table(id int)
insert tblStaff (name, age, address)
OUTPUT inserted.Id INTO @tmp (id)
values (@name, @age, @address)

declare @roleId int = 1 --or whatever
insert tblRoleOfStaff (staffId,roleId)
select id, @roleId
from @tmp

Vous pouvez également insérer plusieurs rôles à la fois.

create table Roles (roleId int identity(1,1) primary key, 
RoleName varchar(50),
isDefaultRole bit default 0
)
--mark some roles as default (`isDefaultRole = 1`)
--the 2nd insert will be
insert tblRoleOfStaff (staffId,roleId)
select id, roleId
from @tmp
cross join Roles
where isDefaultRole = 1
2
Alex Kudryashev