Como inserir vários registros e obter o valor de identidade?

Estou inserindo vários registros em uma tabela A de outra tabela B. Existe uma maneira de obter o valor de identidade de registro de tabela A e atualizar o registro da tabela b sem fazer um 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

Estou usando o MS SQL Server 2005.

0
adicionado editado
Visualizações: 3
A resposta de Andy Irving é a melhor. Os gatilhos são desajeitados e não funcionam bem para operações arbitrárias em sua tabela de destino, especialmente se seu destino for temporário ou apenas intermediário. A resposta de Darren é errada, se você estiver inserindo um conjunto de linhas, o pedido deles na tabela de destino não será necessariamente igual à ordem do seu conjunto. O caminho de Dmitry é ruim porque requer um loop em torno de inserir uma única linha de cada vez, o que é lento desempenho, sempre use conjuntos quando você puder. O caminho de Cory é ruim e ele explicou por que "contan
adicionado o autor clemahieu, fonte
Eu percebo que esta é uma pergunta antiga e especifica o SQL Server 2005, mas como é o primeiro resultado para mostrar a instrução MERGE disponível em 2008 e posterior deve ser mencionado para aqueles que procuram uma solução. MERGE INTO TargetTable USING (SELECT ....) Como Source ON 1 = 2 QUANDO NÃO CORRIGIDO ENTÃO INSERIR .... OUTPUT INSERIDO.ID INTO TempTable (InsertedID)
adicionado o autor oldegreyg, fonte
Você não precisa de uma mesclagem para uma inserção simples. A mesclagem é boa para uma inserção/atualização, mas um exagero para uma inserção simples. A resposta de saída de Andy funcionou para mim e ajudou a remover um bloqueio de índice.
adicionado o autor CodeMonkeyForHire, fonte

7 Respostas

Você pode obter o, inscrevendo-se no número de linha . Isso é possível porque, como é uma identidade, ela é incrementada à medida que você adiciona itens, que estarão na ordem em que você os selecionou.

0
adicionado
Errado, não é garantido que os registros entrem no banco de dados na ordem em que você acha que estão entrando.
adicionado o autor HLGEM, fonte

Tanto quanto eu entendi o problema que você está tendo é que você deseja inserir na tabela A, que tem uma coluna de identidade, e você deseja preservar a identidade da tabela B, o que não.

Para fazer isso, você deve apenas ativar a inserção de identidade na tabela A. Isso permitirá que você defina seus IDs na inserção e, desde que eles não estejam em conflito, você deve estar bem. Então você pode apenas fazer:

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

Não tenho certeza de qual DB você está usando, mas para o SQL Server o comando para ativar a inserção de identidade seria:

set identity_insert A on
0
adicionado
Ele não está tentando atualizar a tabela A, ele está tentando atualizar a tabela B. A tabela B não tem uma coluna de identidade.
adicionado o autor njr101, fonte

Lendo sua pergunta com cuidado, você só quer atualizar a tabela B com base nos novos valores de identidade na tabela A.

Após a inserção terminar, basta executar uma atualização ...

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

Isso pressupõe que a combinação FName/LName pode ser usada para combinar os registros entre as tabelas. Se esse não for o caso, talvez seja necessário adicionar campos extras para garantir que os registros correspondam corretamente.

Se você não tiver uma chave alternativa que permita a correspondência dos registros, isso não fará sentido algum, já que os registros da tabela B não podem ser distinguidos uns dos outros.

0
adicionado

MBelly está certo sobre o dinheiro - Mas, em seguida, o gatilho sempre tentará atualizar a tabela B, mesmo que isso não seja necessário (porque você também está inserindo da tabela C?).

Darren também está correto aqui, você não pode obter várias identidades de volta como um conjunto de resultados. Suas opções estão usando um cursor e pegando a identidade para cada linha que você insere, ou usando a abordagem de Darren de armazenar a identidade antes e depois. Contanto que você saiba o incremento da identidade, isso deve funcionar, desde que você tenha certeza de que a tabela está bloqueada para todos os três eventos.

Se fosse eu, e não fosse tempo crítico, eu iria com um cursor.

0
adicionado

Se você sempre quiser esse comportamento, poderá colocar um gatilho AFTER INSERT na TableA que atualizará a tabela B.

0
adicionado

Eu sugiro usar o tipo uniqueidentifier em vez de identidade. Neste caso, você pode gerar IDs antes da inserção:

update B set NewID = NEWID()

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

Use a cláusula de saída de 2005:

DECLARE @output TABLE (id int)

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

select * from @output

Agora sua variável de tabela possui os valores de identidade de todas as linhas inseridas.

0
adicionado
@munissor, eu sei que este é um segmento antigo, mas confira este artigo de conversa simples sobre o assunto. Veja a seção "Adicionando uma cláusula OUTPUT".
adicionado o autor Mr Moose, fonte
Observe que isso falha miseravelmente quando a tabela A tem um gatilho, porque um bug que a Microsoft se recusa a corrigir. Outra solução alternativa está aqui: stackoverflow.com/q/13198476/2557263
adicionado o autor Alejandro, fonte
@munissor um pouco atrasado, mas você pode fazer output inserted.id, inserted.whateverColumn into @output
adicionado o autor Dennis Rongo, fonte
Mas então, como você atualiza a tabela B? Quero dizer, como você associa cada registro de saída com um registro em B? Se você estiver usando fname, lname como uma chave, é mais simples usar a solução do njr.
adicionado o autor munissor, fonte
@DennisRongo somente se inserted.whateverColumn for outro identificador exclusivo ...
adicionado o autor Mark, fonte