2009-05-29 9 views
5

J'ai une procédure stockée avec plusieurs instructions insert/select. Disons que j'utilise le premier insert pour remplir une table "Manager". Sur insert, un ManagerId (incrémenté automatiquement) est ajouté, mais pas référencé dans l'instruction insert. Je souhaite ensuite utiliser le ManagerId de cette table pour insérer une ligne dans une autre table, où ManagerId est une clé étrangère. Exemple de code comme suit.Récupération de la valeur de colonne auto-incrémentée de la table où plusieurs insertions/sélections dans une procédure stockée unique

USE [TEST] 
GO 
SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 

ALTER PROCEDURE [dbo].[sptInsertNewManager] 
    -- Add the parameters for the stored procedure here 
    @FName varchar(50), 
    @LName varchar(50), 
    @EMail varchar(100), 
    @UserRoleID int, 
    @LANUserID varchar(25), 
    @GroupID int 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

    -- Insert statements for procedure here 
INSERT INTO [Manager]   
      ([FName], 
      [LName], 
      [Email], 
      [UserRoleID], 
      [LANUserID],   
      [ActiveFlag], 
      [GroupID] 
) 
    VALUES 
      (@FName 
      ,@LName 
      ,@EMail 
      ,@UserRoleID 
      ,@LANUserID 
      ,1 
      ,@GroupID); 

COMMIT 

SELECT ManagerId FROM [Manager] AS newManager WHERE LANUserID = @LANUserID; 
     --also insert into Users table. 
    INSERT INTO [dbo].[aspnet_Users] (
     [UserId], 
     [UserName], 
     [LoweredUserName], 
     [ManagerId] 
    ) 
     VALUES (
      NEWID(), 
      @LANUserID, 
      LOWER(@LANUserID), 
      newManager) 
END 

Ceci, évidemment, ne fonctionne pas. C'était ma tentative de résoudre cela. Je suis relativement nouveau à SQL, donc toute aide avec ce problème serait grandement appréciée.

Répondre

7

utilisation SCOPE_IDENTITY() après votre insert pour capturer la dernière valeur d'identité unique à partir de votre portée actuelle:

DECLARE @ID  int 


INSERT ...... 
SELECT @ID=scope_identity() 

utilisation @ID où que vous soyez

Note: SCOPE_IDENTITY() est préféré sur l'IDENTITY plus ancienne car elle donne la dernière valeur Identity dans la portée actuelle, ce qui évite les problèmes des triggers qui s'insèrent dans les tables de log (avec les identités).

Cependant, si vous avez besoin de plusieurs valeurs d'identité (insérer un ensemble de lignes), utilisez la sortie et INTO:

declare @test table (RowID int identity(1,1) primary key not null, RowValue varchar(10) null) 
declare @OutputTable table (RowID int not null) 

insert into @test (RowValue) 
    OUTPUT INSERTED.RowID 
    INTO @OutputTable 
    SELECT 'A' 
    UNION SELECT 'B' 
    UNION SELECT 'C' 
    UNION SELECT 'D' 
    UNION SELECT 'E' 


select * from @OutputTable 

la sortie:

(5 row(s) affected) 
RowID 
----------- 
1 
2 
3 
4 
5 

(5 row(s) affected) 
0

Vous pouvez utiliser la variable globale @@ Identity pour récupérer la dernière valeur d'identité insérée

SELECT @[email protected]@Identity 

vous pouvez également utiliser Scope_Identity et IDENT_ Fonctions actuelles

+1

@@ dentity vous donnera la dernière identité, même si elle n'a pas été de l'insertion dans votre portée (comme si l'insert déclenche un trigger) –

+0

D'accord avec KM, je n'utiliserais jamais @@ identity car tôt ou tard vous aurez des problèmes d'intégrité des données. SAme avec ident_current (vous pouvez obtenir l'identité d'un autre processus juste inséré après le vôtre). Si je veux l'identité que je viens d'insérer j'utilise scope_identity ou sur une version plus récente, vous pouvez utiliser la clause output (Je ne sais pas si cela est arrivé en 2005 ou 2008 comme nous avons sauté 2005) qui a l'avantage de renvoyer l'ensemble valeurs si vous avez exécuté une insertion d'enregistrement mulitple basée sur un ensemble. – HLGEM

2

pour MS Sql Server

Chaque fois que vous insérez un disque et il a la colonne auto-incrément (colonne d'identité en ms-sql langage), vous pouvez l'utilisateur ceci pour récupérer l'ID de la ligne que vous avez inséré:

@id = SCOPE_IDENTITY() 

afin que vous obtenez la valeur de colonne d'identité que votre insert produit, non par les autres utilisateurs pendant le temps de votre code est en cours d'exécution (entre l'insert et d'obtenir l'identité par SCOPE_IDENTITY())

2

Yuck ... vous avez votre proc et la transaction tout tordu ...

Vous voulez que ces deux insertions se produisent dans la même transaction (que je déduis de l'instruction COMMIT au milieu de votre procédure d'origine) . Vous devez donc placer correctement une instruction BEGIN TRANSACTION et COMMIT autour de toutes vos instructions INSERT et SELECT pour isoler les modifications de données.

Considérez ce qui suit:

CREATE PROCEDURE [dbo].[sptInsertNewManager] 
    -- Add the parameters for the stored procedure here 
    @FName varchar(50), 
    @LName varchar(50), 
    @EMail varchar(100), 
    @UserRoleID int, 
    @LANUserID varchar(25), 
    @GroupID int 
AS 
BEGIN 
    -- SET NOCOUNT ON added to prevent extra result sets from 
    -- interfering with SELECT statements. 
    SET NOCOUNT ON; 

DECLARE @ManagerID INT 

BEGIN TRANSACTION  

    -- Insert statements for procedure here 
INSERT INTO [Manager]   
      ([FName], 
      [LName], 
      [Email],  
      [UserRoleID], 
      [LANUserID],   
      [ActiveFlag], 
      [GroupID] 
) 
    VALUES 
       (@FName 
       ,@LName 
       ,@EMail 
      ,@UserRoleID 
      ,@LANUserID 
       ,1 
      ,@GroupID); 

-- Collect the ID you just created 
SELECT @ManagerID = SCOPE_IDENTITY() 


     --also insert into Users table. 
    INSERT INTO [dbo].[aspnet_Users] (
     [UserId], 
     [UserName], 
     [LoweredUserName], 
     [ManagerId] 
    ) 
     VALUES (
       NEWID(), 
       @LANUserID, 
       LOWER(@LANUserID), 
       @ManagerID) -- This is the new identity you just created 

COMMIT 

END 
1

ne Alsó commettras pas au milieu de la transaction, vous voulez que les deux inserts rollback si l'on échoue. Lisez dans Livres en ligne sur le traitement des transactions.

1

Nous pouvons revenir la colonne d'identité comme:

SELECT @@identity as 'Identity' 

et lire cette valeur d'identité dans le code comme:

int ID = Convert.ToInt32(cmdinsert.ExecuteScalar()); 
Questions connexes