Usuário com melhor resposta
Insert em 3 tabelas usando @@identity

Pergunta
-
Fala pessoal,
Mais uma vez venho pedir socorro,
Estava realizando um insert em duas tabelas e como precisava do ID gravado na 1 Tbl utiliza o @@identity no campo da 2 tbl, até ai tudo certo.
Como nada pode ser tão perfeito assim, foi criada a necessidade de gravar este mesmo ID da 1 tbl em uma terceira tbl, nesse caso se utilizar o @@identity pego o ID gravado na 2tbl, o que não me resolve a vida.
Minha pergunta é existe alguma maneira realizar esta gravação ?
posto parte do cod, para que possam entender melhor.
comm.CommandText = @"INSERT INTO Tbl_Fornr(Razao,cnpj,isc_municipal,isc_estadual,id_Empresa,Fantasia,Ativo) Values (@Razao,@cnpj,@isc_municipal,@isc_estadual,@id_Empresa,@Fantasia,@Ativo) INSERT INTO Tbl_EndFor(Logradouro,Numero,Complemento,Bairro,cep,Cidade,id_fornecedor,uf,Tel1,tel2,fax,email,Contato,Sac) Values (@Logradouro,@Numero,@Complemento,@Bairro,@cep,@Cidade,@@IDENTITY,@uf,@Tel1,@tel2,@fax,@email,@Contato,@Sac); //aqui coloquei o @@identity somente para expressar INSERT INTO Tbl_CON(Conta,descricao,Tipo,nada,idforn) Values(@Conta,@descricao,@Tipo,@nada,@@IDENTITY);";
Desde já agradeço quem puder me ajudar.
Att, Wsti.
Respostas
-
WSTI,
Eu recomendo veementemente que você NÃO UTILIZE nem o MAX(..) e nem o @@IDENTITY pois os mesmos possuem problemas e podem não ser adequados ao seu caso. Utilize o SCOPE_IDENTITY() que é mais confiável:
1. O MAX(..) pode causar duplicidades dentro da sua base de dados. Neste caso, se for uma chave primária causará um erro de execução e se não for e o índice unique, se houver, também. Em outros casos, você terá dois registros com o mesmo valor. Esta é a pior escolha para recuperar o último registro inserido dentro de um identity.
2. O @@IDENTITY não é recomendado mesmo no BooksOnline. Veja o que diz:
..."SCOPE_IDENTITY returns the value only within the current scope; @@IDENTITY is not limited to a specific scope"....
...."@@IDENTITY is not a reliable indicator of the most recent user-created identity if the column is part of a replication article. You can use the SCOPE_IDENTITY() function syntax instead of @@IDENTITY"...
Desta forma, fiz um exemplo modificado do exemplo criado pelo Jose.Diz apenas utilizando o SCOPE_IDENTITY() ao invés do @@identity.
-- código 1 declare @ChaveFornr int; INSERT INTO Tbl_Fornr (Razao, cnpj, isc_municipal, isc_estadual, id_Empresa, Fantasia, Ativo) values (@Razao, @cnpj, @isc_municipal, @isc_estadual, @id_Empresa, @Fantasia, @Ativo); set @ChaveFornr= (Select SCOPE_IDENTITY()); INSERT into Tbl_EndFor (Logradouro, Numero, Complemento, Bairro, cep, Cidade, id_fornecedor, uf, Tel1, tel2, fax, email, Contato, Sac) values (@Logradouro, @Numero, @Complemento, @Bairro, @cep, @Cidade, @ChaveFornr, @uf, @Tel1, @tel2, @fax, @email, @Contato, @Sac); INSERT into Tbl_CON (Conta, descricao, Tipo, nada,i dforn) values (@Conta, @descricao, @Tipo, @nada, @ChaveFornr);
Jose.Diz, fiz esta modificação pensando na qualidade do código que outros usuários poderão ter no futuro e desmarquei a postagem como resposta para evitar que outros usuários no futuro utilizem o @@IDENTITY e tenham problemas. Por favor, entenda como uma melhoria no conhecimento.
Roberto Fonseca MCT / MCITP - Database Administrator 2008 MCITP - Database Developer 2008 MCITP - Business Intelligence 2008
- Editado Roberto F FonsecaModerator segunda-feira, 9 de fevereiro de 2015 02:30
- Marcado como Resposta Ricardo Barbosa Cortes terça-feira, 10 de fevereiro de 2015 12:33
Todas as Respostas
-
Boa tarde,
Existim vários modos de solucionar o que você precisa, para uma maior compreensão sua
poderá utilizar da seguinte forma.
Trocar o @@IDENTITY da Terceira tabela por
COALESCE(SELECT MAX(IDFORNECEDOR) FROM Tbl_Fornr,0)
Espero ajudar, simples e eficaz!
-
Deleted
- Marcado como Resposta Wsti domingo, 8 de fevereiro de 2015 18:43
- Não Marcado como Resposta Roberto F FonsecaModerator segunda-feira, 9 de fevereiro de 2015 02:27
-
Fala Rafael,
ficaria assim ??
INSERT INTO Tbl_CON(Conta,descricao,Tipo,nada,idforn) Values(@Conta,@descricao,@Tipo,@nada,COALESCE(SELECT MAX(IDFORNECEDOR) FROM Tbl_Fornr,0));
Pergunto pois não encontrei nenhum exemplo de insert somente select como o COALESCE.
Att, Wsti
-
Jose.Diz Mais uma vez me salvando. Funcionou blz. tudo certinho.
Estou inserindo os dados conforme abaixo, acredito que esteja tudo certo. Pois deixo a cargo do .net.
SqlConnection conn1 = new SqlConnection(@"Data Source=RJ-PC\SQLEXPRESS;Initial Catalog=Di;Integrated Security=True"); SqlCommand comm = new SqlCommand(); comm.Connection = conn1; comm.CommandText = @"declare @ChaveFor int; INSERT INTO Tbl_For(Razao,cnpj,isc_municipal,isc_estadual,id_Empresa,Fantasia,Ativo) Values (@Razao,@cnpj,@isc_municipal,@isc_estadual,@id_Empresa,@Fantasia,@Ativo); Set @Chavefor = @@IDENTITY; INSERT INTO Tbl_EndFor(Logradouro,Numero,Complemento,Bairro,cep,Cidade,id_fornecedor,uf,Tel1,tel2,fax,email,Contato,Sac) Values (@Logradouro,@Numero,@Complemento,@Bairro,@cep,@Cidade,@Chavefor,@uf,@Tel1,@tel2,@fax,@email,@Contato,@Sac); INSERT INTO Tbl_CON(Conta,descricao,Tipo,nada,idforn) Values(@Conta,@descricao,@Tipo,@nada,@Chavefor);"; comm.Parameters.AddWithValue("@Ativo", ativ); comm.Parameters.AddWithValue("@Fantasia", txbNomeFantasia.Text); comm.Parameters.AddWithValue("@Razao", txbRazaoSocial.Text); comm.Parameters.AddWithValue("@cnpj", cpn); comm.Parameters.AddWithValue("@isc_municipal", txbinscMunicpal.Text); comm.Parameters.AddWithValue("@isc_estadual", txbInsEstadual.Text); comm.Parameters.AddWithValue("@id_Empresa", dl.Idempresa); comm.Parameters.AddWithValue("@Logradouro", txbLogradouro.Text); comm.Parameters.AddWithValue("@Numero", txbNumero.Text); comm.Parameters.AddWithValue("@Complemento", txbComplemento.Text); comm.Parameters.AddWithValue("@Bairro", txbBairro.Text); comm.Parameters.AddWithValue("@cep", txbCep.Text); comm.Parameters.AddWithValue("@Cidade", txbCidade.Text); comm.Parameters.AddWithValue("@uf", cbUF.Text); comm.Parameters.AddWithValue("@Tel1", txbTel.Text); comm.Parameters.AddWithValue("@tel2", txbTel2.Text); comm.Parameters.AddWithValue("@fax", txbFax.Text); comm.Parameters.AddWithValue("@email", txbEmail.Text); comm.Parameters.AddWithValue("@Contato", txbContato.Text); comm.Parameters.AddWithValue("@Sac", txbSac.Text); comm.Parameters.AddWithValue("@Conta", NADA); comm.Parameters.AddWithValue("@descricao", txbDescricao.Text); comm.Parameters.AddWithValue("@Tipo", cbTipo.Text); comm.Parameters.AddWithValue("@nada", mtbConta.Text); conn1.Open(); int n = comm.ExecuteNonQuery(); conn1.Close(); if (n > 0) { MessageBox.Show("Registro Inserido com Sucesso."); txbCNPJ.TextMaskFormat = MaskFormat.IncludePromptAndLiterals; carregaGridFornecedores(); foreach (Control ctr in groupBox1.Controls) { if (ctr is TextBox) { ((TextBox)ctr).Clear(); } if (ctr is MaskedTextBox) (ctr as MaskedTextBox).Text = ""; if (ctr is ComboBox) (ctr as ComboBox).SelectedIndex = -1; } lbltbcontiidforn.Text = string.Empty; }
-
WSTI,
Eu recomendo veementemente que você NÃO UTILIZE nem o MAX(..) e nem o @@IDENTITY pois os mesmos possuem problemas e podem não ser adequados ao seu caso. Utilize o SCOPE_IDENTITY() que é mais confiável:
1. O MAX(..) pode causar duplicidades dentro da sua base de dados. Neste caso, se for uma chave primária causará um erro de execução e se não for e o índice unique, se houver, também. Em outros casos, você terá dois registros com o mesmo valor. Esta é a pior escolha para recuperar o último registro inserido dentro de um identity.
2. O @@IDENTITY não é recomendado mesmo no BooksOnline. Veja o que diz:
..."SCOPE_IDENTITY returns the value only within the current scope; @@IDENTITY is not limited to a specific scope"....
...."@@IDENTITY is not a reliable indicator of the most recent user-created identity if the column is part of a replication article. You can use the SCOPE_IDENTITY() function syntax instead of @@IDENTITY"...
Desta forma, fiz um exemplo modificado do exemplo criado pelo Jose.Diz apenas utilizando o SCOPE_IDENTITY() ao invés do @@identity.
-- código 1 declare @ChaveFornr int; INSERT INTO Tbl_Fornr (Razao, cnpj, isc_municipal, isc_estadual, id_Empresa, Fantasia, Ativo) values (@Razao, @cnpj, @isc_municipal, @isc_estadual, @id_Empresa, @Fantasia, @Ativo); set @ChaveFornr= (Select SCOPE_IDENTITY()); INSERT into Tbl_EndFor (Logradouro, Numero, Complemento, Bairro, cep, Cidade, id_fornecedor, uf, Tel1, tel2, fax, email, Contato, Sac) values (@Logradouro, @Numero, @Complemento, @Bairro, @cep, @Cidade, @ChaveFornr, @uf, @Tel1, @tel2, @fax, @email, @Contato, @Sac); INSERT into Tbl_CON (Conta, descricao, Tipo, nada,i dforn) values (@Conta, @descricao, @Tipo, @nada, @ChaveFornr);
Jose.Diz, fiz esta modificação pensando na qualidade do código que outros usuários poderão ter no futuro e desmarquei a postagem como resposta para evitar que outros usuários no futuro utilizem o @@IDENTITY e tenham problemas. Por favor, entenda como uma melhoria no conhecimento.
Roberto Fonseca MCT / MCITP - Database Administrator 2008 MCITP - Database Developer 2008 MCITP - Business Intelligence 2008
- Editado Roberto F FonsecaModerator segunda-feira, 9 de fevereiro de 2015 02:30
- Marcado como Resposta Ricardo Barbosa Cortes terça-feira, 10 de fevereiro de 2015 12:33
-
Prezado Roberto,
Gostaria de agradecer o empenho e preocupação. E sem querem abusar do seu conhecimento. Só fiquei com uma duvida pq a criação de funções que mão geram confiança na implementação ? como no caso do @@identity e o Max ?? Seriam "furos" da própria linguagem, levanto esta questão, pois tenho certeza que será a mesma duvida de qq usuário aqui do fórum que tenha o prazer de ler esta thread ?
Abraços Wsti.
-
Wsti,
No caso do uso do MAX(..) é um erro de conceito e não uma falha da linguagem. Imagine que o seu SQL está sendo acessado por dois usuários exatamente ao mesmo tempo e cada uma das conexões chama do select MAX(...). Digamos que o resultado seja 100... Como o SELECT tem bloqueio compartilhado, imagine que os dois conseguem recuperar o resultado... Só que o resultado recebido será 100 para as duas conexões... Isso causará que 2 linhas tenham o mesmo valor causando problemas na sua base.
No segundo caso, do @@IDENTITY, pode acontecer problemas porque a MS explica que o @@IDENTITY não é associado a uma sessão específica e pode trazer um valor de identity que não foi criado pela sua sessão, mas por outra sessão qualquer... Veja: "@@IDENTITY is not limited to a specific scope". Além disso, o @@IDENTITY pode não ter os resutlados esperados caso você tenha alguma replicação implementada na sua base de dados. Talvez você não tenha hoje, mas isso é normal de acontecer e o seu problema será maior no futuro.
Roberto Fonseca MCT / MCITP - Database Administrator 2008 MCITP - Database Developer 2008 MCITP - Business Intelligence 2008
- Sugerido como Resposta Junior Galvão - MVPMVP quarta-feira, 11 de fevereiro de 2015 14:50