web-dev-qa-db-fra.com

Mise à jour SQL avec numérotation consécutive

Je souhaite mettre à jour une table avec une numérotation consécutive en commençant par 1. La mise à jour comporte une clause where afin que seuls les résultats correspondant à la clause soient renumérotés. Puis-je accomplir cela efficacement sans utiliser de table temporaire?

29
Bryan

Cela dépend probablement de votre base de données, mais voici une solution pour MySQL 5 qui implique l’utilisation d’une variable:

SET @a:=0;
UPDATE table SET field=@a:=@a+1 WHERE whatever='whatever' ORDER BY field2,field3

Vous devriez probablement modifier votre question et indiquer la base de données que vous utilisez.

Edit: j'ai trouvé un solution utilisant T-SQL pour SQL Server. C'est très similaire à la méthode MySQL:

DECLARE @myVar int
SET @myVar = 0

UPDATE
  myTable
SET
  @myvar = myField = @myVar + 1
49
zombat

Pour Microsoft SQL Server 2005/2008. La fonction ROW_NUMBER () a été ajoutée en 2005.

; with T as (select ROW_NUMBER() over (order by ColumnToOrderBy) as RN
        , ColumnToHoldConsecutiveNumber from TableToUpdate
    where ...)
update T
set ColumnToHoldConsecutiveNumber = RN

EDIT: Pour SQL Server 2000:

declare @RN int
set @RN = 0 

Update T
set ColumnToHoldConsecutiveNubmer = @RN
    , @RN = @RN + 1
where ...

REMARQUE: Lorsque j'ai testé l'incrément de @RN qui semblait se produire avant de définir la colonne sur @RN, les valeurs ci-dessus donnent des nombres commençant à 1. 

EDIT: Je viens de remarquer que vous souhaitez créer plusieurs numéros séquentiels dans le tableau. En fonction des besoins, vous pourrez peut-être faire cela en une seule passe avec SQL Server 2005/2008, en ajoutant partition by à la clause over:

; with T as (select ROW_NUMBER() 
        over (partition by Client, City order by ColumnToOrderBy) as RN
     , ColumnToHoldConsecutiveNumber from TableToUpdate)
update T
set ColumnToHoldConsecutiveNumber = RN
28
Shannon Severance

Dans Oracle cela fonctionne:

update myTable set rowColum = rownum
where something = something else

http://download.Oracle.com/docs/cd/B19306_01/server.102/b14200/pseudocolumns009.htm#i1006297

2
Jens Schauder

Si vous voulez créer une nouvelle colonne PrimaryKey, utilisez simplement ceci:

ALTER TABLE accounts ADD id INT IDENTITY(1,1) 
1
eliashdezr

Pour que l'exemple de Shannon fonctionne pleinement, j'ai dû modifier sa réponse:

; WITH CTE AS (
    SELECT ROW_NUMBER() OVER (ORDER BY [NameOfField]) as RowNumber, t1.ID
    FROM [ActualTableName] t1
)
UPDATE [ActualTableName]
    SET Name = 'Depersonalised Name ' + CONVERT(varchar(255), RowNumber)
FROM CTE
    WHERE CTE.Id = [ActualTableName].ID

car sa réponse tentait de mettre à jour T, qui dans son cas était le nom de l’expression de table commune, et jette une erreur.

1
Colin Wiseman

En plus d'utiliser un CTE ou un WITH, il est également possible d'utiliser une mise à jour avec une jointure automatique vers la même table:

UPDATE a
SET a.columnToBeSet = b.sequence
FROM tableXxx a
INNER JOIN
(
   SELECT ROW_NUMBER() OVER ( ORDER BY columnX ) AS sequence, columnY, columnZ
   FROM tableXxx
   WHERE columnY = @groupId AND columnY = @lang2
) b ON b.columnY = a.columnY AND b.columnZ = a.columnZ

La table dérivée, alias b, est utilisée pour générer la séquence via la fonction ROW_NUMBER () avec d'autres colonnes formant une clé primaire virtuelle . En règle générale, chaque ligne nécessite une valeur de séquence unique.

La clause WHERE est facultative et limite la mise à jour aux lignes qui remplissent les conditions spécifiées.

La table dérivée est ensuite jointe à la même table, alias a, rejoignant les colonnes de clé primaire virtuelle avec la colonne à mettre à jour définie sur la séquence générée.

1
Kevin Swann

J'ai utilisé cette technique pendant des années pour peupler des ordinaux et des colonnes numérotées séquentiellement. Cependant, j'ai récemment découvert un problème lors de son exécution sur SQL Server 2012. Il semblerait que le moteur de requête applique la mise à jour en interne à l'aide de plusieurs threads et que la partie du prédicat de UPDATE ne soit pas gérée de manière thread-safe. Pour que cela fonctionne à nouveau, je devais reconfigurer le degré de parallélisme maximal de SQL Server en un cœur.

EXEC sp_configure 'show advanced options', 1;
GO
RECONFIGURE WITH OVERRIDE;
GO
EXEC sp_configure 'max degree of parallelism', 1;
GO
RECONFIGURE WITH OVERRIDE;
GO

DECLARE  @id int
SET @id = -1
UPDATE dbo.mytable
SET @id = Ordinal = @id + 1

Sans cela, vous constaterez que la plupart des numéros séquentiels sont dupliqués dans le tableau.

1
user2412960

Joindre à une table de nombres? Il s’agit d’une table supplémentaire, mais ce ne serait pas temporaire - vous garderiez la table des nombres comme un utilitaire.

Voir http://web.archive.org/web/20150411042510/http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-nauxiliary-numbers-table.html

ou

http://www.sqlservercentral.com/articles/Advanced+Querying/2547/

(Ce dernier nécessite une inscription gratuite, mais je trouve que c'est une très bonne source de conseils et de techniques pour MS SQL Server, et beaucoup de choses s'appliquent à toute implémentation SQL).

0
Val