2014-06-17 1 views
0

J'ai une table avec ID (identité) et XID (int) qui est ma colonne auto-incrémentation personnalisée. J'utilise un trigger au lieu d'insert pour maintenir XID, mais je reçois des doublons.maintien d'une colonne d'incrémentation automatique personnalisée


tableau

XTABLE (identité ID, XID int)


déclenchement - au lieu d'insert

insert into [xtable] (XID) 
select [x].[NextavailableID] 
from inserted [i] 
cross apply 
(
    select coalesce(max([t].[XID]), 0) + 1 [NextavailableID] 
    from [xtable] [t] 
) [x]; 

En supposant inséré = 1 ligne.

Ce déclencheur n'empêche pas les doublons dans la colonne XID. Des idées sur la façon de le changer?

+2

Pourquoi avez-vous besoin d'une deuxième colonne d'incrémentation automatique? Est-ce un exemple simplifié? Il pourrait y avoir une solution alternative plus facile à maintenir. – GarethD

+0

@GarethD - Ceci est un exemple simplifié. Chaque entreprise doit avoir un identifiant unique. Donc xtable aurait aussi un CompanyID fk – Aducci

+0

Quel SQL Server? 2008 [R2], 2012, 2014? –

Répondre

1

J'ai fini par créer une autre table pour stocker le dernier incrément. Dans le déclencheur, à l'intérieur d'une transaction, je sélectionne à partir de la nouvelle table avec des conseils (UPDLOCK, ROWLOCK).


Table

Info (LastId int) 

déclencheur - au lieu d'insérer

declare @nextId int; 

begin tran t1 

    set @nextId = (select top 1 LastId from Info with (UPDLOCK, ROWLOCK)) + 1; 

    update Info set LastId = nextId; 

commit tran t1 

insert into [xtable] (XID) 
select @nextId 
from inserted [i] 

2

Le problème est que lorsque vous avez plusieurs lignes étant insérées vous utilisez le même ID suivant disponible pour toutes les lignes, vous auriez besoin d'ajouter ROW_NUMBER() pour assurer la XID était unique dans l'insert:

insert into [xtable] (XID) 
select [x].[NextavailableID] + ROW_NUMBER() OVER (ORDER BY i.ID) 
from inserted [i] 
cross apply 
(
    select coalesce(max([t].[XID]), 0) [NextavailableID] 
    from [xtable] [t] WITH (TABLOCK, HOLDLOCK) 
) [x]; 

En ce qui concerne la prévention des doublons, vous pouvez utiliser des indicateurs de table pour verrouiller xtable lorsque vous obtenez le maximum xid. L'inconvénient de l'utilisation de ces verrous est que vous obtiendrez une super-impasse. Vous devriez avoir une contrainte/un index unique sur cette colonne, car cela empêchera les doublons, mais il en résultera également des exceptions lorsqu'une condition de concurrence est remplie. En fin de compte, quelle que soit la méthode que vous choisissez, vous devrez faire une sorte de sacrifice.

+3

Cela fonctionnerait-il si plusieurs instructions d'insertion étaient exécutées en parallèle? –

+0

Désolé je n'étais pas clair, je suppose que inséré était seulement 1 ligne. Je reçois les doublons lorsque plusieurs instructions d'insertion se produisent simultanément – Aducci

+0

@Aducci Et c'est pourquoi la réponse était d'utiliser une colonne 'IDENTITY' à la place d'une colonne personnalisée – Lamak

1

SQL Server 2012+:

j'utiliser sequences.

D'abord, je voudrais créer une nouvelle séquence

CREATE SEQUENCE dbo.XTable_XID 
START WITH 1 -- You should replace the starting value 
INCREMENT BY 1 
-- CACHE 50; -- Optimization: read documentation first 
GO 

puis j'utiliser NEXT VALUE FOR pour générer de nouvelles valeurs ainsi:

-- #1 I would use this function when I insert rows `into dbo.XTable` 
INSERT INTO [dbo].[XTable] (Col1, Col2, Col3, ..., XID) 
VALUES ('A', 123, 1000.50, (NEXT VALUE FOR dbo.XTable_XID)); 

ou

-- #2: Also, you could rewrite the trigger thus: 
insert into [xtable] (XID) 
select (NEXT VALUE FOR dbo.XTable_XID) 
from inserted [i] 

Je vous utilisez d'abord méthode que vous pouvez supprimer ce déclencheur s'il est utilisé uniquement pour générer ces ID. J'utiliserais la solution # 1.

+

Je voudrais créer un index unique:

CREATE UNIQUE INDEX IUN_XTable_XID 
ON dbo.XTable (XID); 
+1

Je n'ai pas pu tester cette solution, mais j'apprécie l'information sur les séquences. Je ne savais pas à leur sujet – Aducci

+0

@Aducci: Avez-vous essayé? Avez-vous eu des problèmes pour essayer cette solution? Si oui, pouvez-vous me dire quelle (s) erreur (s) avez-vous eue? –

Questions connexes