2010-06-23 5 views
4

J'ai une table qui est utilisée pour stocker un ID numérique incrémentant (de type INT). Il contient une seule ligne. L'ID est incrémenté en utilisant une requête:Procédure stockée renvoyant le résultat d'un UPDATE

UPDATE TOP(1) MyTable 
WITH(TABLOCKX) 
SET NextID = NextID + 1 

Je voudrais passer cela dans une procédure stockée qui retourne la valeur qui était dans la colonne NextID avant l'incrémenter, mais je suis pas sûr comment faire en utilisant Paramètres OUTPUT. Toute aide serait appréciée.

+0

I invité vous ne pouvez pas utiliser [identité] (http://msdn.microsoft.com/en-us/library/aa933196% 28SQL.80% 29.aspx) type. –

+0

@Grzegorz Pas une option dans ce cas. Parfois, je dois définir la valeur à un nombre arbitraire - soit dans le logiciel de manuel dans sql management studio. –

Répondre

3

pour SQL Server 2005+, essayez:

CREATE PROCEDURE dbo.Get_New_My_Table_ID 
    @current_id INT = NULL OUTPUT -- Declared OUTPUT parameter 
AS 
BEGIN TRANSACTION 

UPDATE TOP(1) MyTable WITH(TABLOCKX) 
    SET NextID = NextID + 1 
    OUTPUT DELETED.NextID 

COMMIT TRANSACTION 

RETURN 0 
GO 

les résultats de OUTPUT ne ont pas besoin pour entrer dans une table réelle, il peut s'agir d'un ensemble de résultats.

le tester:

declare @MyTable table (NextID int) 
INSERT INTO @MyTable VALUES (1234) 


SELECT 'BEFORE',* FROM @MyTable 

PRINT '------------<<<<UPDATE>>>>---------' 
UPDATE TOP(1) @MyTable 
    SET NextID = NextID + 1 
    OUTPUT DELETED.NextID 
PRINT '------------<<<<UPDATE>>>>---------' 

SELECT 'AFTER',* FROM @MyTable 

SORTIE:

(1 row(s) affected) 
     NextID 
------ ----------- 
BEFORE 1234 

(1 row(s) affected) 

------------<<<<UPDATE>>>>--------- 
NextID 
----------- 
1234 

(1 row(s) affected) 

------------<<<<UPDATE>>>>--------- 
     NextID 
----- ----------- 
AFTER 1235 

(1 row(s) affected) 
+0

Merci KM. Ça marche pour moi.Puisque la requête est plus simple (et vraisemblablement plus efficace) que celle de Tom, j'ai accepté votre réponse. –

2

Vous voudrez peut-être ajouter une vérification d'erreur, etc. J'ai également supposé que la table est une table à une rangée.

CREATE PROCEDURE dbo.Get_New_My_Table_ID 
    @current_id INT = NULL OUTPUT -- Declared OUTPUT parameter 
AS 
BEGIN 
    BEGIN TRANSACTION 

    SELECT 
     @current_id = COALESCE(next_id, 0) 
    FROM 
     dbo.My_Table WITH (TABLOCK, HOLDLOCK) 

    UPDATE dbo.My_Table 
    SET next_id = @current_id + 1 

    COMMIT TRANSACTION 
END 
GO 

Pour utiliser la procédure stockée:

DECLARE @my_id INT 

EXEC dbo.Get_New_My_Table_ID @current_id = @my_id OUTPUT 
+0

@Tom veut que la valeur * avant l'incrément * soit retournée. –

+0

Merci Tom, ça marche pour moi. L'idée d'utiliser une sélection initiale avant la mise à jour m'était venue à l'esprit, mais je pensais à tort que HOLDLOCK ne pouvait pas être utilisé avec TABLOCKX, donc je ne pouvais pas voir un moyen de garder le verrou. On dirait que ça peut. Vous m'avez également présenté la déclaration COALESCE, dont je n'étais pas au courant! –

+0

@Martin Vrai, mais je peux facilement adapter sa solution. –

3

Dans SQL2005 ou plus tard, les valeurs précédentes pour les valeurs mises à jour peuvent être récupérées à l'aide de la clause SORTIE.

Étant donné qu'une seule valeur sera retournée, je ne sais pas comment cela se compare à l'approche de Tom. Je pense que Tom's sera plus rapide car il y a une lecture supplémentaire mais pas de surcharge pour créer une variable de table. (Edit: et de mes cours doit encore lire la variable de table aussi bien!)

CREATE PROC blah 
@OldId int OUTPUT 
AS 

DECLARE @OldIds table(NextID int); 


UPDATE TOP(1) MyTable 
WITH(TABLOCKX) 
SET NextID = NextID + 1 
OUTPUT DELETED.NextID INTO @OldIds 

SELECT @OldId = NextID 
FROM @OldIds 
+0

Merci Martin. +1 pour ça. J'ai décidé d'accepter la solution de Tom parce qu'elle évite la nécessité d'une table temporaire. Semblait légèrement plus simple. –

+0

@Andy - Oui, je suis d'accord. Il est dommage que '@OldId = DELETED.NextID' ne semble pas fonctionner. –

+0

La clause 'OUTPUT' est le chemin à parcourir, mais vous l'avez ruiné en utilisant la table temporaire. 'OUTPUT' n'a pas besoin d'aller dans une table, ce peut être un ensemble de résultats, voir ma réponse. –

Questions connexes