2008-12-09 5 views
0

Je sais que je peux mettre à jour un seul enregistrement comme celui-ci - mais alors comment avoir accès à l'ID de l'enregistrement qui a été mis à jour? (J'utilise MSSQL je ne peux pas utiliser Oracles RowId)Quel est le meilleur moyen de mettre à jour un seul enregistrement via SQL et obtenir l'ID de l'enregistrement qui a été mis à jour? (Java/MSSQL)

update myTable 
set myCol = 'foo' 
where itemId in (select top 1 itemId from myTable) 

Si je Peforming un insert que je pouvais utiliser getGeneratedKeys pour obtenir la valeur du champ id, mais je ne pense pas qu'il y ait un équivalent une mise à jour?

Je sais que je peux utiliser un resultset Défilant pour faire ce que je veux

-à-dire

stmt = conn.prepareStatement("select top 1 myCol, itemId from myTable", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); 
ResultSet resultSet = stmt.executeQuery(); 
if(resultSet.first()){ 
    resultSet.updateString(1, "foo"); 
    resultSet.updateRow(); 
    String theItemId = resultSet.getString(1) 
} 
resultSet.close(); 

mais je suis préoccupé par la performance en tant que test montre les délais d'attente de verrouillage sous charge et je me demandais s'il y avait un moyen meilleur/plus simple? Pour terminer ce problème ... Lorsque nous migrerons vers MSSQL2005, nous mettrons à niveau notre code pour utiliser la réponse de Rich. Dans la version actuelle, nous avons utilisé les indications de verrouillage: (UPDLOCK ROWLOCK READPAST) pour atténuer les problèmes de performance que notre code original a montré.

Répondre

6

Cet exemple fonctionne très bien dans MSSQL 2005 ...

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 

DROP TABLE [dbo].[TEST_TABLE] 
GO 

CREATE TABLE [dbo].[TEST_TABLE](
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [name] [nvarchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, 
CONSTRAINT [PK_TEST_TABLE] PRIMARY KEY CLUSTERED 
(
    [id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 


-- An insert which will return the identity 
INSERT INTO [dbo].[TEST_TABLE] ([name]) 
OUTPUT inserted.id 
VALUES('Test 1') 

-- Another insert which will return the identity 
INSERT INTO [dbo].[TEST_TABLE] ([name]) 
OUTPUT inserted.id 
VALUES('Test 2') 

-- Now an update which will return the identity 
UPDATE [dbo].[TEST_TABLE] 
SET [name] = 'Updated Test 1' 
OUTPUT inserted.id 
WHERE [name] = 'Test 1' 

SELECT id, [name] FROM [dbo].[TEST_TABLE] 

Et plus précisément à votre question ...

update myTable 
set myCol = 'foo' 
output inserted.itemid 
where itemId in (select top 1 itemId from myTable) 
+1

Si vous voulez capturer la valeur dans le script (par exemple, pour le renvoyer au lieu de l'afficher comme résultat), créez une variable de table locale ("declare @output table (itemid int)") et faites "output inserted.itemid dans @output". Vous pouvez ensuite sélectionner à partir de là pour une utilisation ultérieure. – GalacticCowboy

+0

Cet exemple est exactement ce que je cherche ... Je suis actuellement bloqué sur MSSQL 2000 mais le plan de migration pour 2008 est en train de se passer en mars, alors je vais garder ça à l'esprit pour l'instant. Merci – user44538

+1

J'ai du mal à voir pourquoi je suis descendu, un commentaire aiderait –

-4

Pour le serveur insert MSQSQL a le paramètre @@Identity qui a l'ID du dernier enregistrement inséré.

+0

obsolète, utilisez scope_identity() – keithwarren7

+0

et ne fonctionne pas non plus pour les mises à jour - c'est la dernière valeur * inséré *. L'identité @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ – GalacticCowboy

0

je ferais ce qui suit:

Begin Tran 

update myTable 
set myCol = 'foo' 
where itemId in (select top 1 itemId from myTable) 

select top 1 itemId from myTable 

Commit Tran 
+0

Cela fonctionnerait-il encore dans un système multi-thread sous charge? – user44538

0

Est-ce que cela a à être dans une seule déclaration? En fin de compte ce serait mieux une procédure stockée

Create Procedure doMyUpdate 

@Id int output 

as 

Set @Id = (select top 1 itemId from myTable) 
update myTable 
set myCol = 'foo' 
where itemId = @Id 

une autre façon serait d'utiliser mot-clé th RETURN et intégré dans le paramètre RETURN_VALUE ...

Create Procedure doMyUpdate 

as 

Declare @Id int 
Set @Id = (select top 1 itemId from myTable) 

update myTable 
set myCol = 'foo' 
where itemId = @Id 

RETURN @Id 
+0

Il ne doit pas être dans une seule déclaration. Mais il doit fonctionner dans un environnement multithread. L'astuce consiste peut-être à créer une clé unique et à l'utiliser dans le cadre de ma déclaration de mise à jour (c'est-à-dire dans une nouvelle colonne). Puis-je faire le select avec myUniqueCol = 'bar35636'? – user44538

Questions connexes