¿Cómo insertar múltiples registros y obtener el valor de identidad?

Estoy insertando varios registros en una tabla A de otra tabla B. ¿Hay alguna manera de obtener el valor de identidad de la tabla A y actualizar la tabla b sin tener que hacer un cursor?

Create Table A
(id int identity,
Fname nvarchar(50),
Lname nvarchar(50))

Create Table B
(Fname nvarchar(50),
Lname nvarchar(50),
NewId int)

Insert into A(fname, lname)
SELECT fname, lname
FROM B

Estoy usando MS SQL Server 2005.

0
agregado editado
Puntos de vista: 4
La respuesta de Andy Irving es la mejor. Los desencadenadores son torpes y no funcionan bien para operaciones arbitrarias en su tabla de destino, especialmente si su objetivo es temporal o simplemente intermedio. La respuesta de Darren es incorrecta, si está insertando un conjunto de filas, su orden en la tabla objetivo no es necesariamente el mismo que el orden de su conjunto. El camino de Dmitry es malo porque requiere un bucle para insertar una sola fila a la vez, que es de bajo rendimiento, siempre use conjuntos cuando pueda. El camino de Cory es malo y explicó por qué, "siempre y cuando n
agregado el autor clemahieu, fuente
Me doy cuenta de que esta es una vieja pregunta y especifica SQL Server 2005, pero dado que es el primer resultado en mostrar la declaración MERGE disponible en 2008 y posterior, debería mencionarse para aquellos que buscan una solución. FUSIÓN EN TargetTable USING (SELECT ....) AS Source ON 1 = 2 CUANDO NO ESTÁ ENCUADRE ENTONCES INSERTAR .... OUTPUT insert.ID INTO TempTable (InsertedID)
agregado el autor oldegreyg, fuente
No necesita una fusión para un simple inserto. Merge es bueno para una inserción/actualización, pero exagerado para una simple inserción en. La respuesta de salida de Andy funcionó para mí y ayudó a quitar un bloqueo de índice.
agregado el autor CodeMonkeyForHire, fuente

7 Respuestas

Puede obtenerla uniéndose en el número de fila . Esto es posible porque, como se trata de una identidad, aumentará a medida que agregue elementos, que estarán en el orden en que los está seleccionando.

0
agregado
Incorrecto, no se garantiza que los registros entren en la base de datos en el orden en el que crees que están ingresando.
agregado el autor HLGEM, fuente

Por lo que yo entiendo, el problema que está teniendo es que quiere INSERTAR en la Tabla A, que tiene una columna de identidad, y desea conservar la identidad de la Tabla B que no lo hace.

Para hacerlo, solo debe activar la inserción de identidad en la tabla A. Esto le permitirá definir sus identificaciones en la inserción y, siempre que no entren en conflicto, debería estar bien. Entonces puedes hacer:

Insert into A(identity, fname, lname) SELECT newid, fname, lname FROM B

No estoy seguro de qué base de datos está utilizando, pero para el servidor sql, el comando para activar la inserción de identidad sería:

set identity_insert A on
0
agregado
No intenta actualizar la tabla A, intenta actualizar la tabla B. La tabla B no tiene una columna de identidad.
agregado el autor njr101, fuente

Leyendo cuidadosamente su pregunta, solo desea actualizar la tabla B en función de los nuevos valores de identidad en la tabla A.

Una vez que finaliza la inserción, solo ejecuta una actualización ...

UPDATE B
SET NewID = A.ID
FROM B INNER JOIN A
     ON (B.FName = A.Fname AND B.LName = A.LName)

Esto supone que la combinación FName/LName se puede usar para hacer coincidir las claves de los registros entre las tablas. Si no es el caso, es posible que deba agregar campos adicionales para garantizar que los registros coincidan correctamente.

Si no tiene una clave alternativa que le permita hacer coincidir los registros, entonces no tiene ningún sentido, ya que los registros en la tabla B no pueden distinguirse entre sí.

0
agregado

MBelly tiene razón con el dinero, pero entonces el activador siempre intentará actualizar la tabla B incluso si no es necesario (¿porque también está insertando desde la tabla C?).

Darren también es correcto aquí, no se pueden obtener múltiples identidades como resultado. Sus opciones están usando un cursor y tomando la identidad de cada fila que inserta, o utilizando el enfoque de Darren de almacenar la identidad antes y después. Siempre que sepa el incremento de la identidad, esto debería funcionar, siempre y cuando se asegure de que la tabla esté bloqueada para los tres eventos.

Si fuera yo, y no era crítico en el tiempo, iría con un cursor.

0
agregado

Si siempre quiere este comportamiento, podría colocar un desencadenador DESPUÉS DE INSERTAR en la Tabla A que actualizará la tabla B.

0
agregado

Sugiero usar el tipo uniqueidentifier en lugar de la identidad. En este caso, puede generar ID antes de la inserción:

update B set NewID = NEWID()

insert into A(fname,lname,id) select fname,lname,NewID from B
0
agregado

Use la cláusula de salida del 2005:

DECLARE @output TABLE (id int)

Insert into A (fname, lname)
OUTPUT inserted.ID INTO @output
SELECT fname, lname FROM B

select * from @output

ahora su variable de tabla tiene los valores de identidad de todas las filas que inserta.

0
agregado
@munissor, sé que este es un hilo antiguo, pero echa un vistazo a este artículo de conversación simple sobre el tema. Mire la sección "Agregar una cláusula OUTPUT".
agregado el autor Mr Moose, fuente
Tenga en cuenta que esto falla miserablemente cuando la tabla A tiene un activador, porque es un error que Microsoft se niega a corregir. Otra solución está aquí: stackoverflow.com/q/13198476/2557263
agregado el autor Alejandro, fuente
@munissor un poco tarde pero puede hacer output inserted.id, inserted.whateverColumn en @output
agregado el autor Dennis Rongo, fuente
Pero, ¿cómo se actualiza la tabla B? Quiero decir, ¿cómo asocias cada registro de @output con un registro en B? Si usa fname, lname como clave, entonces es más sencillo usar la solución de njr.
agregado el autor munissor, fuente
@DennisRongo solo si inserted.whateverColumn es otro identificador único ...
agregado el autor Mark, fuente