none
Insert em 3 tabelas usando @@identity RRS feed

  • 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.

    domingo, 8 de fevereiro de 2015 16:21

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



    segunda-feira, 9 de fevereiro de 2015 02:26
    Moderador

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!

    domingo, 8 de fevereiro de 2015 18:16
  • 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
    domingo, 8 de fevereiro de 2015 18:24
  • 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

    domingo, 8 de fevereiro de 2015 18:27
  • 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;
                        }

    domingo, 8 de fevereiro de 2015 18:51
  • 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



    segunda-feira, 9 de fevereiro de 2015 02:26
    Moderador
  • 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.

    segunda-feira, 9 de fevereiro de 2015 08:34
  • 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

    segunda-feira, 9 de fevereiro de 2015 13:28
    Moderador