none
Uso de variáveis do MySQL via MySqlCommand RRS feed

  • Pergunta

  • Bom dia a todos!

    Tenho o seguinte comando (SQL) para sincronizar duas tabelas:

    "insert into tabela_destino (id, campo1, campo2)
    select @cod:=@cod+1 as id, campo1, campo2 from tabela_origem, (select @cod:=(select max(id) from tabela_destino)) as cod;"

    O comando atende perfeitamente minha necessidade, que é inserir os registros na tabela "tabela_destino" sem que tenha problemas de id duplicados, ou seja, já estou verificando o maior id e incrementando automaticamente para cada novo registro! (esse campo não é auto_increment)

    Meu problema: não consigo executar esse comando utilizando o MySqlCommand, pois quando tento executar (ExecuteNonQuery()) recebo uma exceção informando que o parâmetro "@cod" não foi setado... "@cod" é uma variável que será instanciada e controlada pelo MySQL...

    Alguém sabe como posso executar essa string no MySQL pela minha aplicação(C#)?

    Desde já agradeço

    Filipi Brentegani

    segunda-feira, 25 de fevereiro de 2013 13:39

Respostas

  • Por que você não faz em dois  tempos? Acredito que fica um código mais bonito:

    string sql = "SELECT MAX(id) FROM tabela_destino";
    MySqlCommand cmd = new MySqlCommand(sql, connection);
    int id = int.Parse(cmd.ExecuteScalar()) + 1;
    
    sql = "INSERT INTO tabela_destino (id, campo1, campo2)"
       + " SELECT @newCod as id, campo1, campo2" 
       + " FROM tabela_origem";
    
    MySqlCommand cmd = new MySqlCommand(sql, conn);
    cmd.Parameters.AddWithValue("@newCod", id);
    cmd.ExecuteNonQuery();

    Quanto a gravação concorrente é só dar uma pesquisada (Handling Data Concurrency irá trazer mais resultados), tem bastante material na internet que explica como evitar esse tipo de situação.



    Ao infinito e além!


    • Editado Fabio R. Luz segunda-feira, 25 de fevereiro de 2013 17:43
    • Marcado como Resposta Filipi Brentegani terça-feira, 26 de fevereiro de 2013 11:30
    segunda-feira, 25 de fevereiro de 2013 17:42

Todas as Respostas

  • Acontece que '@' é considerado um parâmetro para o ADO.NET. Considere o seguinte SQL:

    INSERT INTO tabela_destino (id, campo1, campo2)
        SELECT @newCod as id, campo1, campo2 
             FROM tabela_origem

    @newCod seria uma variável, que precisa ser setada pelo MySqlCommand, exemplo:

    MySqlCommand cmd = new MySqlCommand(sql);
    cmd.Parameters.AddWithValue("@newCod", seuNovoCodigo);
    A partir daqui, @newCod terá um valor, que nesse caso será a variável: seuNovoCodigo. Esta variável pode ser, e será no seu caso, o retorno de um outro sql somando + 1.



    Ao infinito e além!

    segunda-feira, 25 de fevereiro de 2013 15:04
  • Obrigado pela resposta Fabio!

    Realmente, o MySqlCommand reconhece o o trecho "@cod" da string como um parâmetro! Mas eu preciso que aconteça o contrário, pois isso não é um parâmetro!

    Usando da forma que eu havia escrito, eu consigo movimentar quantos registros existirem na tabela "tabela_origem", inserindo-os na "tabela_destino", já fazendo que o id sofra um 'auto_incremento' a partir do último id inserido na "tabela_destino"... Esse recurso que estou usando é algo parecido com CURSOR utilizado em outros SGBDs... Não sei exatamente se isso que estou fazendo é o mesmo recurso.

    OBS: Vale apenas lembrar que o comando está correto, o select está retornando a informação no formato que ela deve ser inserida! O único problema é o MySqlCommand interpretar o @ como prefixo de um parâmetro!

    Caso não consiga executar o comando na íntegra, terei de usar a solução que você me sugeriu, vai custar um pouco mais de código, e pensando em gravação concorrente, terei que tomar alguns outros cuidados!

    Caso consiga fazer como planejei a princípio, posto a resolução aqui!

    Obrigado Fabio!!!! 

    Filipi Brentegani


    • Editado Filipi Brentegani segunda-feira, 25 de fevereiro de 2013 16:00 Informação adicional, melhora na explicação!
    segunda-feira, 25 de fevereiro de 2013 15:57
  • Por que você não faz em dois  tempos? Acredito que fica um código mais bonito:

    string sql = "SELECT MAX(id) FROM tabela_destino";
    MySqlCommand cmd = new MySqlCommand(sql, connection);
    int id = int.Parse(cmd.ExecuteScalar()) + 1;
    
    sql = "INSERT INTO tabela_destino (id, campo1, campo2)"
       + " SELECT @newCod as id, campo1, campo2" 
       + " FROM tabela_origem";
    
    MySqlCommand cmd = new MySqlCommand(sql, conn);
    cmd.Parameters.AddWithValue("@newCod", id);
    cmd.ExecuteNonQuery();

    Quanto a gravação concorrente é só dar uma pesquisada (Handling Data Concurrency irá trazer mais resultados), tem bastante material na internet que explica como evitar esse tipo de situação.



    Ao infinito e além!


    • Editado Fabio R. Luz segunda-feira, 25 de fevereiro de 2013 17:43
    • Marcado como Resposta Filipi Brentegani terça-feira, 26 de fevereiro de 2013 11:30
    segunda-feira, 25 de fevereiro de 2013 17:42
  • Fabio, estava prestes a implementar algo próximo a que foi sugerido por você, quando localizei a solução para a minha dúvida:

    No manual do MySQL, em "8.4. UserDefined Variables", é mostrado como utilizar variáveis no banco, e eu vi uma forma diferente de declarar e acessar as variáveis, usando o caractere aspas simples!

    O comando ficou o seguinte:

    "insert into tabela_destino (id, campo1, campo2)
    select @'cod':=@'cod'+1 as id, campo1, campo2 from tabela_origem, (select @'cod':=(select max(id) from tabela_destino)) as cod;"

    Assim o MySqlCommand não interpreta as variáveis de banco como parâmetros, e eu consigo utilizar o processamento do próprio MySQL, fazendo que o processo seja mais rápido, e já garante um eventual problema de gravações concorrentes na mesma tabela!

    Obrigado pela força!

    Abraço

    segunda-feira, 25 de fevereiro de 2013 20:18