sql - txt - mantener una columna personalizada de incremento automático
importar txt a sql server 2012 (3)
Tengo una tabla con ID (identidad) y XID (int) que es mi columna personalizada de incremento automático. Estoy usando un activador en lugar de insertar para mantener XID, pero obtengo duplicados.
mesa
xtable (ID de identidad, XID int)
gatillo - en lugar de insertar
insert into [xtable] (XID)
select [x].[NextavailableID]
from inserted [i]
cross apply
(
select coalesce(max([t].[XID]), 0) + 1 [NextavailableID]
from [xtable] [t]
) [x];
Suponiendo insertado = 1 fila.
Este disparador no evita duplicados en la columna XID. ¿Alguna idea sobre cómo cambiarla?
El problema es que si tiene varias filas insertadas, está utilizando la misma ID disponible para todas las filas, deberá agregar ROW_NUMBER()
para asegurarse de que el xid sea único en la inserción:
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];
Con respecto a la prevención de duplicados, puede usar sugerencias de tabla para bloquear xtable
al obtener el xid
máximo.
El inconveniente de usar estos bloqueos es que se bloqueará. Debería tener una restricción / índice único en esta columna ya que esto evitará duplicados, sin embargo, también dará lugar a excepciones cuando se cumpla una condición de carrera. En definitiva, sea cual sea el método que elija, tendrá que hacer algún tipo de sacrificio.
SQL Server 2012+:
Yo usaría secuencias .
Primero crearía una nueva secuencia
CREATE SEQUENCE dbo.XTable_XID
START WITH 1 -- You should replace the starting value
INCREMENT BY 1
-- CACHE 50; -- Optimization: read documentation first
GO
y luego usaría NEXT VALUE FOR para generar nuevos valores así:
-- #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));
o
-- #2: Also, you could rewrite the trigger thus:
insert into [xtable] (XID)
select (NEXT VALUE FOR dbo.XTable_XID)
from inserted [i]
Si está utilizando el primer método, podría soltar ese activador si solo se usa para generar estos ID. Usaría la solución n. ° 1.
+
Crearía un índice único:
CREATE UNIQUE INDEX IUN_XTable_XID
ON dbo.XTable (XID);
Terminé creando otra tabla para almacenar el último incremento. En el desencadenador, dentro de una transacción, selecciono de la nueva tabla con sugerencias ( ROWLOCK
, ROWLOCK
).
mesa
Info (LastId int)
gatillo - en lugar de insertar
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]