SQL Server 2008 - Insérer l'ID de l'enregistrement nouvellement créé dans une table, dans deux autres tables

J'ai trois tables:

DECLARE @UserTable TABLE(
        [UserId] [int] IDENTITY(1,1) NOT NULL,
        UserName varchar(100))

DECLARE @UserRoles TABLE(
        [UserRoleId] [int] IDENTITY(1,1) NOT NULL,
        RoleName varchar(100),
        UserId int)

DECLARE @UserProjects TABLE(
        [UserProjectId] [int] IDENTITY(1,1) NOT NULL,
        ProjectName varchar(100),
        UserId int)

Ce que je veux faire, c'est que chaque fois que je crée un nouvel enregistrement dans @UserTable , je veux prendre l'ID de cet enregistrement et créer un nouvel enregistrement dans @UserRoles et @UserProjects . En insérant des enregistrements un par un, je peux utiliser SCOPE_IDENTITY pour obtenir le nouvel ID, puis effectuer les insertions 2 et 3 en utilisant la valeur de ...

Mais quand j'essaye de faire cela avec quelque chose comme 100 enregistrements insérés dans @UserTable, cela ne fonctionnera pas parce que c'est un encart en masse. Quelle est la meilleure manière de s'occuper de ça? Utilisez un curseur? Je suis ouvert aux idées, car je n'ai jamais eu à le faire auparavant ... ce serait simple avec une boucle FOREACH , mais pour autant que je sache, SQL ne gère pas ces de la même manière que nous attendrions Java ou C#, non?

0
@ Muhammed-ali Je ne suis pas sûr de comprendre. J'ai une procédure stockée qui crée une table temporaire, insère une valeur initiale, puis met à jour cette table avec des informations. Ensuite, je prends tous les enregistrements dans la table temporaire et les insère dans une autre table (la table des utilisateurs). Je veux créer un déclencheur pour aller sur l'insertion de table d'utilisateur, qui peuplera alors la table de rôles et de projets ... mais je continue à obtenir des erreurs en créant le déclencheur. Où est le meilleur endroit pour mettre la gâchette, avec d'autres codes dans la p
ajouté l'auteur SalarianEngineer, source
Vous aurez besoin de créer After Insert Trigger sur UserTable qui gérera n'importe quel nombre d'insertions dans cette table fera des insertions en cascade dans d'autres tables.
ajouté l'auteur M.Ali, source

5 Réponses

À moins que je ne me trompe, ce que vous essayez de faire, c'est d'appliquer l'intégrité référentielle sur vos tables et de tenir compte des actions en cascade. Il y a un article décent ici qui montre comment mettre cela en place.

2
ajouté
Juste ce dont j'avais besoin, merci!
ajouté l'auteur SalarianEngineer, source

Essayez cette solution:

-- Parameters
DECLARE @UserName VARCHAR(100), @RoleName VARCHAR(100), @ProjectName VARCHAR(100);
SELECT  @UserName = 'User CocoJambo',
        @RoleName = 'Role MamboJambo',
        @ProjectName = 'Project Jumbo';
-- End of Parameters

DECLARE @NewUserID TABLE (UserID INT);

INSERT  @UserTable (UserName)
OUTPUT  inserted.UserId INTO @NewUserID (UserID)
VALUES  (@UserName);

INSERT  @UserRoles (UserID, RoleName)
SELECT  u.UserId, @RoleName
FROM    @UserTable u;

INSERT  @UserProjects (UserId, ProjectName)
SELECT  u.UserId, @ProjectName
FROM    @UserTable u;
0
ajouté
Si cette solution ne vous aide pas alors vous devriez fournir plus d'infos: par exemple quelles données (quelles colonnes) importez-vous? Importez-vous un ou plusieurs fichiers dans SQL Server DB (un fichier par table peut-être)?
ajouté l'auteur Bogdan Sahlean, source

Vous aurez besoin de définir un déclencheur sur votre UserTable qui fera l'insertion en cascade dans les autres tables pour vous quelque chose comme ça

CREATE Trigger tr_ForInserts
ON UserTable
FOR INSERT
AS
BEGIN
 SET NOCOUNT ON;

   /*Get all the new insert into a temp table */

   SELECT * INTO #TempTable 
   FROM inserted 

 /*Insert Statement to Insert recods in UserRoles Table */

   INSERT INTO UserRoles (Column1,Column2,Column3,...) 
   SELECT  Column1,Column2,Column3
   FROM #TempTable 


 /*Insert Statement to Insert recods in UserProjects Table */ 

   INSERT INTO UserProjects (Column4,Column5,Column6,...) 
   SELECT  Column4,Column5,Column6
   FROM #TempTable 

END
0
ajouté
@ Shiva La raison pour laquelle j'ai utilisé une table temporaire voir ici ce que votre code fait :) sqlfiddle.com/# ! 3/6fc64/1
ajouté l'auteur M.Ali, source
Les variables @Shiva Table sont bonnes et plus rapides si vous savez que vous n'insérerez qu'un petit nombre de lignes mais que faire si vous devez insérer beaucoup de lignes qui pourraient finir par manger toute votre mémoire ??? allez-vous aller dans la définition de votre déclencheur et le modifier chaque fois que vous avez à faire un grand nombre d'insertions en vrac? ou allez-vous faire un calcul et laisser tous vos utilisateurs savoir combien de lignes ils peuvent ajouter en même temps ??? ou est-il préférable d'utiliser des tables temporaires et laissez le serveur sql faire le travail :
ajouté l'auteur M.Ali, source
aussi sur les tables Temp si vous traitez beaucoup de données, vous pouvez créer des index pour accélérer les opérations et oui j'aurais dû laisser tomber la table à la fin de toutes les opérations. Mais je suppose que nous essayons tous de mettre OP dans la bonne direction, je ne peux pas lui donner le code qu'il peut copier coller dans sa base de données pour le faire fonctionner, avec les informations fournies dans la question.
ajouté l'auteur M.Ali, source
Il n'est pas nécessaire de créer une table temporaire et de tout sélectionner, puisque l'OP ne veut que l'ID.
ajouté l'auteur Shiva, source
D'accord. J'ai mis à jour mon code pour traiter les INSULES EN VRAC. Cependant, vous devriez utiliser une variable TABLE, pas une table temporaire (plus de surcharge, plus grande portée, etc.). :)
ajouté l'auteur Shiva, source
@Shiva: les variables de table sont remplies dans tempdb comme les tables temporaires, et les tables logiques de trigger (insérées et supprimées) vont aussi dans tempdb, ce qui fait deux fois plus de données dans tempdb dans un déclencheur insert (x3 pour trigger). Il n'y a aucun avantage à utiliser les variables de tables temporaires que les tables temporaires (Inside sql server K.Delaney) et autres: cybersql.blogspot.fr/2009/12/…
ajouté l'auteur ARA, source

Vous pouvez écrire un INSERT TRIGGER comme ça. Lorsque de nouvelles lignes sont insérées dans votre table des utilisateurs, ce déclencheur se déclenchera pour chaque instruction (et non chaque ligne) exécutée. Donc, dans le cas d'une insertion BULK, nous devons utiliser une variable de table temporaire qui contiendra tous les ID utilisateurs nouvellement insérés et ensuite effectuer des insertions dans la table UserRoles et UserProjects.

CREATE TRIGGER trg_Insert_Role_And_Project
ON [UserTable]
FOR INSERT
AS
Begin
    Declare @NewUserIDsTable TABLE
    ( NewUserID INT NOT NULL )

    INSERT INTO @NewUserIDsTable SELECT ID FROM INSERTED

    INSERT INTO UserRoles (UserId, RoleName) 
    SELECT NewUserID, 'Default Role' 
    FROM @NewUserIDsTable 


    INSERT INTO UserProjects (UserId, ProjectName) 
    SELECT NewUserID, 'Default Project'
    FROM @NewUserIDsTable 

End

Est-ce que RoleName et ProjectName dans les tables @UserRoles et @UserProject ont des valeurs par défaut? Pour cet exemple de code, j'ai utilisé les valeurs par défaut de 'Rôle par défaut' et 'Default Project' .

0
ajouté
Les trois tables ont été arbitrairement inventées pour la question posée, mais je comprends ce que vous voulez dire. Essentiellement, j'ai besoin de créer un enregistrement vide dans les deux autres tables chaque fois qu'un nouvel utilisateur est créé, et plus tard lors de l'enregistrement de l'utilisateur, ces deux tables seront mises à jour (de cette façon, l'enregistrement existe déjà t doivent être complétés en une seule séance selon les exigences du client).
ajouté l'auteur SalarianEngineer, source
La raison pour laquelle j'ai utilisé une table temporaire voir ici ce que votre code fait :) sqlfiddle.com/#!3/6fc64/1
ajouté l'auteur M.Ali, source
@Alain_Deloin Vous avez raison. J'ai corrigé le déclencheur pour traiter le scénario d'insertion en bloc. Pour l'arrière-plan, voir stackoverflow.com/a/5806230/325521
ajouté l'auteur Shiva, source
@SalarianEngineer est d'accord. J'ai enlevé cette suggestion de ma réponse :)
ajouté l'auteur Shiva, source
select @ NewUserId = L'ID utilisateur FROM INSERTED ne fonctionne pas avec une insertion en bloc (plusieurs enregistrements sont insérés)
ajouté l'auteur ARA, source

Avec de vraies tables (et non des variables) vous pouvez créer un trigger:

CREATE TABLE UserTable( [UserId] [int] IDENTITY(1,1) NOT NULL, UserName varchar(100))

CREATE TABLE UserRoles ( [UserRoleId] [int] IDENTITY(1,1) NOT NULL, RoleName varchar(100), UserId int)

CREATE TABLE UserProjects ( [UserProjectId] [int] IDENTITY(1,1) NOT NULL, ProjectName varchar(100), UserId int)

GO

if object_id('UserTableTrigger') is not null
    drop trigger UserTableTrigger
go
create trigger UserTableTrigger ON Usertable
for INSERT
as
begin
    insert into UserRoles(RoleName,UserId)
    select 'Role_'+UserName, inserted.UserId
    from inserted
    insert into UserProjects(ProjectName,UserId)
    select 'Project_'+UserName, inserted.UserId
    from inserted
end
go

Si vous voulez le vérifier:

insert into UserTable (UserName)
select 'User_'+name from master..spt_values

select * from UserTable
left join UserRoles on UserTable.USerId = UserRoles.UserId
left join UserProjects on UserTable.USerId = UserProjects.UserId
0
ajouté