ActiveDelphi - Índice do Fórum ActiveDelphi
.: O site do programador Delphi! :.
 
 FAQFAQ   PesquisarPesquisar   MembrosMembros   GruposGrupos   RegistrarRegistrar 
 PerfilPerfil   Entrar e ver Mensagens ParticularesEntrar e ver Mensagens Particulares   EntrarEntrar 

Muito demorado para gravar na tabela com loop?
Ir à página 1, 2, 3, 4  Próximo
 
Novo Tópico   Responder Mensagem    ActiveDelphi - Índice do Fórum -> Delphi
Exibir mensagem anterior :: Exibir próxima mensagem  
Autor Mensagem
adriano_servitec
Colaborador
Colaborador


Registrado: Sexta-Feira, 30 de Janeiro de 2004
Mensagens: 17618

MensagemEnviada: Seg Ago 28, 2017 6:02 pm    Assunto: Muito demorado para gravar na tabela com loop? Responder com Citação

Tenho 168.939 registro para inserir na tabela mais preciso verificar se existe o ID na tabela se existir faz um update se não insert

E este método deixa muito lento.

Código:
function Tdm.VerificaSeTemID(const sNomeTable: String; iID: Integer): Boolean;
  function GetNomeCampoPK(const sNomeTable: String): String;
  begin
    with qryAcoes do
    begin
      Close;
      SQL.Clear;
      SQL.Text := ' SELECT * FROM ' + sNomeTable;
      Open;
      Result := Fields[0].FieldName;
    end;
  end;

var
  Fieled_Pk: String;
begin
  Fieled_Pk := GetNomeCampoPK(sNomeTable);
  with qryAcoes do
  begin
    Close;
    SQL.Clear;
    SQL.Text := ' SELECT * FROM ' + sNomeTable + ' WHERE ' + Fieled_Pk +
      ' = :pID ';
    ParamByName('pID').AsInteger := iID;
    // ShowMessage(SQL.Text);
    Open;
    if not IsEmpty then
      Result := True // se for true então é update
    else
      Result := False; // se for false é insert
  end;
end;


Estes métodos ai faz a consulta se tem na tabela o ID

só que passo isso no loop todos as 168.939 vezes

Código:
for j := 0 to Pred(Lista.Count) do
      begin
        if Trim(Lista[j]) = EmptyStr then
          Continue;

        Lista2.DelimitedText := Lista[j];

        with dm.qryGrade do
        begin
          // retorna o id que vem da web
          // se tiver ID na tabela então update, se não intere na tabela
          if FListaTablesControls.GetVerificaSeTemID('grade',
            StrToIntDef(Lista2[0], 0)) then
            Edit
          else
            Append;
          FieldByName('id_cadastro').AsInteger := StrToIntDef(Lista2[1], 0);
          FieldByName('id_produto').AsInteger := StrToIntDef(Lista2[2], 0);
          FieldByName('id_grade_atributo_valor').Value := Lista2[3];
          FieldByName('id_usuario_alterou').Value := Lista2[4];
          FieldByName('codigo_barra_pai').Value := Lista2[5];
          FieldByName('codigo_barra').Value := Lista2[6];
          FieldByName('codigo_interno').Value := Lista2[7];
          FieldByName('qtd_atual').Value := Lista2[8];
          FieldByName('qtd_minima').Value := Lista2[9];

          FieldByName('qtd_locacao').Value := Lista2[10];
          FieldByName('qtd_locacao_locado').Value := Lista2[11];
          FieldByName('valor_custo').Value := Lista2[12];
          FieldByName('valor_varejo_avista').Value := Lista2[13];
          FieldByName('valor_varejo_aprazo').Value := Lista2[14];
          FieldByName('valor_atacado_avista').Value := Lista2[15];
          FieldByName('valor_atacado_aprazo').Value := Lista2[16];
          FieldByName('ativo').Value := Lista2[17];
          FieldByName('data_alteracao').AsDateTime :=
            StrToDateTimeDef(Lista2[18], 0);
          FieldByName('data_sincronismo').AsDateTime :=
            StrToDateTimeDef(Lista2[19], 0);
          FieldByName('id_web').AsInteger := StrToIntDef(Lista2[20], 0);
          Post;
          Gauge1.Progress := j + 1;
        end;
        Application.ProcessMessages;
      end;


Se eu desativo esta consulta ai fica rapido a consulta se não demora muito.

O que devo fazer para melhorar isso?

Obrigado.
_________________
Jogo seu smartphone? Acesse o link e confira.
https://play.google.com/store/apps/details?id=br.com.couldsys.rockdrum
https://play.google.com/store/apps/details?id=br.com.couldsys.drumsetfree
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
imex
Moderador
Moderador


Registrado: Sexta-Feira, 7 de Janeiro de 2011
Mensagens: 11666

MensagemEnviada: Seg Ago 28, 2017 8:49 pm    Assunto: Responder com Citação

Boa noite,

Como aparentemente os dados retornados pela query da função GetNomeCampoPK não são utilizados, somente os nomes dos campos, sugiro que seja acrescentado um filtro para que não seja retornado nenhum registro do BD. Ex:

Código:
      SQL.Text := ' SELECT * FROM ' + sNomeTable + ' WHERE 0 = 1';


E como a tabela é sempre a mesma no looping, acho que essa função poderia ser executada somente uma vez antes de começar o looping.

Espero que ajude


Editado pela última vez por imex em Qui Set 28, 2023 11:38 am, num total de 1 vez
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
wjuniordias
Profissional
Profissional


Registrado: Sexta-Feira, 16 de Março de 2012
Mensagens: 667

MensagemEnviada: Ter Ago 29, 2017 8:09 am    Assunto: Re: Muito demorado para gravar na tabela com loop? Responder com Citação

Já tentou usar o comando "insert or update"?

Em relação ao loop, o arrayDML resolveria o problema da lentidão, fiz alguns testes em alguns projetos aqui na empresa e tive uma performance considerável.

http://www.clipatecinformatica.com.br/2017/08/comando-array-dml-firedac-no-delphi.html
_________________
"O sábio nunca diz tudo o que pensa, mas pensa sempre tudo o que diz." (Aristóteles)
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular Visitar a homepage do Usuário MSN Messenger
leo_cj
Colaborador
Colaborador


Registrado: Sábado, 26 de Março de 2011
Mensagens: 1335

MensagemEnviada: Ter Ago 29, 2017 9:46 am    Assunto: Responder com Citação

Se o problema for essas verificações, o que você pode fazer é o seguinte:

- Criar uma tabela temporária com as mesmas colunas da tabela desejada.
- Incluir as informações da lista nessa tabela temporária

feito isso, você realiza um update com select e um insert com select ex:

Supondo que minha tabela seja Cliente
Citação:
ID_Cliente Integer Identity(1,1),
NM_Cliente Varchar(20),
NR_Celular Varchar(18)


criaria então a tabela temporária com a mesma estrutura, mas com o campo ID_Cliente apenas como Integer, sem o auto incremento (identity)

uma vez com todos os registros na temporária vamos as instruções de inclusão e update
Código:
UPDATE Cli
SET
    Cli.NM_Cliente = CT.NM_Cliente,
    Cli.NR_Cliente = CT.NR_Cliente
FROM
    Cliente AS Cli
    INNER JOIN ClienteTMP AS CT
        ON Cli.ID_Cliente = CT.ID_Cliente

Nesse update, pegamos apenas as informações da tabela temporária que existem na tabela principal.

Código:
INSERT INTO Cliente (NM_Cliente, NR_Celular)
SELECT NM_Cliente,
       NR_Celular
  FROM ClienteTMP CT
WHERE NOT EXISTS(SELECT 1
                   FROM Cliente
                  WHERE ID_Cliente = CT.ID_Cliente)


Nesse insert, verificamos os códigos que estão na tabela temporária mas não existem na tabela principal.
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
natanbh1
Colaborador
Colaborador


Registrado: Terça-Feira, 15 de Março de 2011
Mensagens: 3093
Localização: Belo Horizonte - MG

MensagemEnviada: Ter Ago 29, 2017 10:11 am    Assunto: Responder com Citação

Uma alternativa seria testar o Locate ao invés do seu método para verificar existe o item para ver se melhora a performance.

Outra sugestão é, se for manter o seu método, ao invés de buscar todos os campos, busque somente os campos necessários.

Troque:
Código:
SQL.Text := ' SELECT * FROM ' + sNomeTable;

Por:
Código:
SQL.Text := ' SELECT Campo1 FROM ' + sNomeTable; // somente os campos necessários

_________________
''A persistência é o caminho para o êxito.''
Charlie Chaplin
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular Enviar E-mail
adriano_servitec
Colaborador
Colaborador


Registrado: Sexta-Feira, 30 de Janeiro de 2004
Mensagens: 17618

MensagemEnviada: Ter Ago 29, 2017 11:53 am    Assunto: Responder com Citação

imex escreveu:
Boa noite,

Como aparentemente os dados retornados pela query da função GetNomeCampoPK não são utilizados, somente os nomes dos campos, sugiro que seja acrescentado um filtro para que não seja retornado nenhum registro do BD. Ex:

Código:
      SQL.Text := ' SELECT * FROM ' + sNomeTable + ' WHERE 0 = 1';


E como a tabela é sempre a mesma no looping, acho que essa função poderia ser executada somente uma vez antes de começar o looping.

Espero que ajude


Ja arrumei e mesmo assim o tempo é longo 1 hora e 14 minutos

Meu problema é na verificação que tenho que fazer a cada looping se insere ou edita o campo

arrayDML (gostei desta ideia)

Mais não deu certo na hora de gravar no banco
Código:
 procedure TfrmConfiguracoes.BtnDownloadClick(Sender: TObject);
var
  Lista, Lista2: TStringList;
  j, l: Integer;
  DS: TDataSource;
  FListaTablesControls: TListaTablesControls;
  Grid: TDBGrid;
  sSQLInsert, sSQLUpdate: String;
  iNumInserts: Integer;
begin
  FListaTablesControls := TListaTablesControls.Create;
  try
    lblCronometro.Caption := FormatDateTime('ss.zzz', fTempo);

    sSQLInsert := ' INSERT INTO grade( ' +
      ' id_cadastro, id_produto, id_grade_atributo_valor, id_usuario_alterou, '
      + ' codigo_barra_pai, codigo_barra, codigo_interno, qtd_atual, qtd_minima, '
      + ' qtd_locacao, qtd_locacao_locado, valor_custo, valor_varejo_avista,  '
      + ' valor_varejo_aprazo, valor_atacado_avista, valor_atacado_aprazo, ' +
      ' porc_varejo_avista, porc_varejo_aprazo, porc_atacado_avista,  ' +
      ' porc_atacado_aprazo, ativo,  ' +
      ' data_alteracao, data_sincronismo, id_web' + ' VALUES ( ' +
      ' :Pid_cadastro, :Pid_produto, :Pid_grade_atributo_valor, :Pid_usuario_alterou, '
      + ' :Pcodigo_barra_pai, :Pcodigo_barra, :Pcodigo_interno, :Pqtd_atual, :Pqtd_minima, '
      + ' :Pqtd_locacao, :Pqtd_locacao_locado, :Pvalor_custo, :Pvalor_varejo_avista,  '
      + ' :Pvalor_varejo_aprazo, :Pvalor_atacado_avista, :Pvalor_atacado_aprazo, '
      + ' :Pporc_varejo_avista, :Pporc_varejo_aprazo, :Pporc_atacado_avista,  '
      + ' :Pporc_atacado_aprazo, :Pativo,  ' +
      ' :Pdata_alteracao, :Pdata_sincronismo, :Pid_web ';

    sSQLUpdate := ' UPDATE grade  ' +
      ' SET id_cadastro = :Pid_cadastro, id_produto = :Pid_produto, ' +
      '     id_grade_atributo_valor = :id_grade_atributo_valor,  ' +
      '     id_usuario_alterou = :Pid_usuario_alterou, codigo_barra_pai = :Pcodigo_barra_pai, '
      + '     codigo_barra = :Pcodigo_barra, codigo_interno = :Pcodigo_interno,  '
      + '     qtd_atual = :Pqtd_atual, qtd_minima = :Pqtd_minima, ' +
      '     qtd_locacao = :Pqtd_locacao, qtd_locacao_locado = :Pqtd_locacao_locado, '
      + '     valor_custo = :Pvalor_custo, valor_varejo_avista = :Pvalor_varejo_avista, '
      + '     valor_varejo_aprazo = :Pvalor_varejo_aprazo,      ' +
      '     valor_atacado_avista = :Pvalor_atacado_avista, valor_atacado_aprazo = :Pvalor_atacado_aprazo, '
      + '     porc_varejo_avista = :Pporc_varejo_avista, ' +
      '     porc_varejo_aprazo = :Pporc_varejo_aprazo, porc_atacado_avista = :Pporc_atacado_avista, '
      + '     porc_atacado_aprazo = :Pporc_atacado_aprazo,   ' +
      '     ativo = :Pativo, data_alteracao = :Pdata_alteracao, ' +
      '     data_sincronismo = :Pdata_sincronismo, id_web = :Pid_web  ' +
      '  WHERE id_web = :Pid_web ';

    Lista := TStringList.Create;
    Lista2 := TStringList.Create;
    try
      Lista.LoadFromFile('grade.csv', TEncoding.UTF8);
      Lista2.StrictDelimiter := True;
      Lista2.Delimiter := ';'; // aqui defino qual separador
      Gauge1.MaxValue := Lista.Count;
      // iniciar cronometro
      fMomento := GetTickCount;
      crono.Enabled := True;
      Lista.BeginUpdate;

      if dm.qryGrade.Active then
        dm.qryGrade.Close;
      dm.qryGrade.SQL.Add(sSQLInsert);

      iNumInserts := Lista.Count;
      dm.qryGrade.Params.ArraySize := iNumInserts;

      dm.qryGrade.DisableControls;
      for j := 0 to Pred(Lista.Count) do
      begin
        if Trim(Lista[j]) = EmptyStr then
          Continue;

        Lista2.DelimitedText := Lista[j];

        with dm.qryGrade do
        begin
          // retorna o id que vem da web
          // se tiver ID na tabela então update, se não intere na tabela
          // ShowMessage(Lista2[20]);
//          if FListaTablesControls.GetVerificaSeTemID('grade',
//            StrToIntDef(Lista2[20], 0)) then
//            SQL.Add(sSQLUpdate)
//          else
//            SQL.Add(sSQLInsert);
          ParamByName('Pid_cadastro').AsInteger := StrToIntDef(Lista2[1], 0);
          ParamByName('Pid_produto').AsInteger := StrToIntDef(Lista2[2], 0);
          ParamByName('Pid_grade_atributo_valor').AsString := Lista2[3];
          ParamByName('Pid_usuario_alterou').AsInteger := StrToIntDef(Lista2[4], 0);
          ParamByName('Pcodigo_barra_pai').asString := Lista2[5];
          ParamByName('Pcodigo_barra').asString := Lista2[6];
          ParamByName('Pcodigo_interno').asString := Lista2[7];
          ParamByName('Pqtd_atual').AsFloat := StrToFloatDef(Lista2[8], 0);
          ParamByName('Pqtd_minima').AsFloat := StrToFloatDef(Lista2[9], 0);
          ParamByName('Pqtd_locacao').AsFloat := StrToFloatDef(Lista2[10], 0);
          ParamByName('Pqtd_locacao_locado').AsFloat := StrToFloatDef(Lista2[11], 0);
          ParamByName('Pvalor_custo').AsCurrency := StrToCurrDef(Lista2[12], 0);
          ParamByName('Pvalor_varejo_avista').AsCurrency := StrToCurrDef(Lista2[13], 0);
          ParamByName('Pvalor_varejo_aprazo').AsCurrency := StrToCurrDef(Lista2[14], 0);
          ParamByName('Pvalor_atacado_avista').AsCurrency := StrToCurrDef(Lista2[15],0);
          ParamByName('Pvalor_atacado_aprazo').AsCurrency := StrToCurrDef(Lista2[16],0);
          ParamByName('Pporc_varejo_avista').AsFloat := StrToFloatDef(Lista2[17],0);
          ParamByName('Pporc_varejo_aprazo').AsFloat := StrToFloatDef(Lista2[18],0);
          ParamByName('Pporc_atacado_avista').AsFloat := StrToFloatDef(Lista2[19],0);
          ParamByName('Pporc_atacado_aprazo').AsFloat := StrToFloatDef(Lista2[20],0);
          ParamByName('Pativo').AsString := Lista2[21];
          ParamByName('Pdata_alteracao').AsDateTime :=
            StrToDateTimeDef(Lista2[22], 0);
          ParamByName('Pdata_sincronismo').AsDateTime :=
            StrToDateTimeDef(Lista2[23], 0);
          ParamByName('Pid_web').AsInteger := StrToIntDef(Lista2[24], 0);

          Gauge1.Progress := j + 1;
        end;
        Application.ProcessMessages;
      end;

      if iNumInserts > 0 then
        dm.qryGrade.Execute(iNumInserts, 0);

      dm.qryGrade.Active := false;

    finally
      Lista.EndUpdate;
      dm.qryGrade.EnableControls;
      FreeAndNil(Lista);
      FreeAndNil(Lista2);
      lblTotQtd.Caption := FormatFloat('#,0',
        Grid.DataSource.DataSet.RecordCount);
      // parar cronometro
      crono.Enabled := false;
      // desaloca da memoria
      FreeAndNil(Grid);
    end;
  finally

    FreeAndNil(FListaTablesControls);
  end;
end;


Ao executar da o erro
---------------------------
Debugger Exception Notification
---------------------------
Project WCSync.exe raised exception class EPgNativeException with message '[FireDAC][Phys][PG][libpq] ERROR: syntax error at or near "VALUES"'.
---------------------------
Break Continue Help
---------------------------


Alias queria saber se é possível fazer o update e insert juntos no código.
_________________
Jogo seu smartphone? Acesse o link e confira.
https://play.google.com/store/apps/details?id=br.com.couldsys.rockdrum
https://play.google.com/store/apps/details?id=br.com.couldsys.drumsetfree
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
adriano_servitec
Colaborador
Colaborador


Registrado: Sexta-Feira, 30 de Janeiro de 2004
Mensagens: 17618

MensagemEnviada: Ter Ago 29, 2017 11:59 am    Assunto: Responder com Citação

natanbh1 escreveu:
Uma alternativa seria testar o Locate ao invés do seu método para verificar existe o item para ver se melhora a performance.

Outra sugestão é, se for manter o seu método, ao invés de buscar todos os campos, busque somente os campos necessários.

Troque:
Código:
SQL.Text := ' SELECT * FROM ' + sNomeTable;

Por:
Código:
SQL.Text := ' SELECT Campo1 FROM ' + sNomeTable; // somente os campos necessários


Ja troquei, continua lento para grande volume de dados

Eu recebo um arquivo csv para gravar na base de dados.
_________________
Jogo seu smartphone? Acesse o link e confira.
https://play.google.com/store/apps/details?id=br.com.couldsys.rockdrum
https://play.google.com/store/apps/details?id=br.com.couldsys.drumsetfree
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
imex
Moderador
Moderador


Registrado: Sexta-Feira, 7 de Janeiro de 2011
Mensagens: 11666

MensagemEnviada: Ter Ago 29, 2017 12:10 pm    Assunto: Responder com Citação

Qual banco de dados (e versão) você está utilizando?
Acho que talvez seja possível eliminar essa parte do código se o banco que você está utilizando tiver um comando como o Merge ou semelhante.
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
adriano_servitec
Colaborador
Colaborador


Registrado: Sexta-Feira, 30 de Janeiro de 2004
Mensagens: 17618

MensagemEnviada: Ter Ago 29, 2017 1:10 pm    Assunto: Responder com Citação

imex escreveu:
Qual banco de dados (e versão) você está utilizando?
Acho que talvez seja possível eliminar essa parte do código se o banco que você está utilizando tiver um comando como o Merge ou semelhante.
Postgres 9.6.4
_________________
Jogo seu smartphone? Acesse o link e confira.
https://play.google.com/store/apps/details?id=br.com.couldsys.rockdrum
https://play.google.com/store/apps/details?id=br.com.couldsys.drumsetfree
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
adriano_servitec
Colaborador
Colaborador


Registrado: Sexta-Feira, 30 de Janeiro de 2004
Mensagens: 17618

MensagemEnviada: Ter Ago 29, 2017 1:11 pm    Assunto: Responder com Citação

leo_cj escreveu:
Se o problema for essas verificações, o que você pode fazer é o seguinte:

- Criar uma tabela temporária com as mesmas colunas da tabela desejada.
- Incluir as informações da lista nessa tabela temporária

feito isso, você realiza um update com select e um insert com select ex:

Supondo que minha tabela seja Cliente
Citação:
ID_Cliente Integer Identity(1,1),
NM_Cliente Varchar(20),
NR_Celular Varchar(1Cool


criaria então a tabela temporária com a mesma estrutura, mas com o campo ID_Cliente apenas como Integer, sem o auto incremento (identity)

uma vez com todos os registros na temporária vamos as instruções de inclusão e update
Código:
UPDATE Cli
SET
    Cli.NM_Cliente = CT.NM_Cliente,
    Cli.NR_Cliente = CT.NR_Cliente
FROM
    Cliente AS Cli
    INNER JOIN ClienteTMP AS CT
        ON Cli.ID_Cliente = CT.ID_Cliente

Nesse update, pegamos apenas as informações da tabela temporária que existem na tabela principal.

Código:
INSERT INTO Cliente (NM_Cliente, NR_Celular)
SELECT NM_Cliente,
       NR_Celular
  FROM ClienteTMP CT
WHERE NOT EXISTS(SELECT 1
                   FROM Cliente
                  WHERE ID_Cliente = CT.ID_Cliente)


Nesse insert, verificamos os códigos que estão na tabela temporária mas não existem na tabela principal.
Se eu não conseguir com a ideia do array vou ver esta Leo.
_________________
Jogo seu smartphone? Acesse o link e confira.
https://play.google.com/store/apps/details?id=br.com.couldsys.rockdrum
https://play.google.com/store/apps/details?id=br.com.couldsys.drumsetfree
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
adriano_servitec
Colaborador
Colaborador


Registrado: Sexta-Feira, 30 de Janeiro de 2004
Mensagens: 17618

MensagemEnviada: Ter Ago 29, 2017 2:02 pm    Assunto: Responder com Citação

adriano_servitec escreveu:
imex escreveu:
Qual banco de dados (e versão) você está utilizando?
Acho que talvez seja possível eliminar essa parte do código se o banco que você está utilizando tiver um comando como o Merge ou semelhante.
Postgres 9.6.4


Vamos la Imex,

Preciso verificar o seguinte
Se o arquivo que esta vindo a ultima linha a onde tem o ID que vem do arquivo for igual ao campo id_web(tela local) e a data de alteracao que vem do arquivo for maior que a data de sincronismo da tabela local então é um update se não um insert e se nenhuma das condições for então significa que ambos estao iguais no arquivo e na tabela.


Da pra fazer com merge no postgres?
_________________
Jogo seu smartphone? Acesse o link e confira.
https://play.google.com/store/apps/details?id=br.com.couldsys.rockdrum
https://play.google.com/store/apps/details?id=br.com.couldsys.drumsetfree
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
strak2012
Colaborador
Colaborador


Registrado: Segunda-Feira, 13 de Janeiro de 2014
Mensagens: 1518
Localização: Maceió - AL

MensagemEnviada: Ter Ago 29, 2017 2:35 pm    Assunto: Responder com Citação

Consultar para inserir ou atualizar via programação num loop é algo muito demorado e inviável.
Das melhores solução mencionada estão:

1ª - Verificar se há suporte para o comando insert or update a ação de atualizar ou inserir fica com o SGDB em questão, isso vai diminuir em metade o tempo gasto
2ª - Trabalhar com comando Array DML fantástico e eficiente, pois muitas operações pode ser executada de uma unica vez, isso há uma ganho de performance sem igual.

Se não há possibilidade para a 1ª então recomenda que seja criado procedure stored, que faça o papel de verificar e inserir ou atualizar quando houver o tal registro desta forma voce passa o papel de verificar e atualizar ou inserir para o SGDB em questão.

Ainda não coloquei em pratica os comando Array DML apenas dei uma lida por alto, só será valido se estiver a usar componentes com suporte para tal, mais é uma baita solução.


bom é isso boa sorte.
_________________
Tudo podemos quando tudo sabemos!
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular Enviar E-mail MSN Messenger
imex
Moderador
Moderador


Registrado: Sexta-Feira, 7 de Janeiro de 2011
Mensagens: 11666

MensagemEnviada: Ter Ago 29, 2017 3:04 pm    Assunto: Responder com Citação

adriano_servitec escreveu:
Se o arquivo que esta vindo a ultima linha a onde tem o ID que vem do arquivo for igual ao campo id_web(tela local) e a data de alteracao que vem do arquivo for maior que a data de sincronismo da tabela local então é um update se não um insert e se nenhuma das condições for então significa que ambos estao iguais no arquivo e na tabela.

Pelo que entendi acho que essa verificação pode ser feita só uma vez na aplicação logo no início para ver se o looping deve ser executado ou não.


adriano_servitec escreveu:
Da pra fazer com merge no postgres?

Pelo que vi o Postgre tem o comando Merge. Com o Merge (ou o Insert or Update em outros bancos como o Firebird) é possível especificar algumas condições para ver se deve ser executado um Insert ou um Update. Segue abaixo um exemplo onde é verificado se o campo id_web passado por parâmetro existe ou não para executar um Update ou um Insert respectivamente:

Código:
MERGE INTO Grade g
USING (VALUES(:Pid_web as id_web,
              :Pid_cadastro as id_cadastro,
              :Pid_produto as id_produto,
              :Pid_grade_atributo_valor as id_grade_atributo_valor)) v
ON v.id_web = g.id_web
WHEN NOT MATCHED
  INSERT (id_web, id_cadastro, id_produto, id_grade_atributo_valor)
      VALUES(v.id_web, v.id_cadastro, v.id_produto, v.id_grade_atributo_valor)
WHEN MATCHED
  UPDATE SET
      id_cadastro = v.id_cadastro,
      id_produto = v.id_produto,
      id_grade_atributo_valor = v.id_grade_atributo_valor;


Espero que ajude
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
adriano_servitec
Colaborador
Colaborador


Registrado: Sexta-Feira, 30 de Janeiro de 2004
Mensagens: 17618

MensagemEnviada: Ter Ago 29, 2017 3:07 pm    Assunto: Responder com Citação

strak2012 escreveu:
Consultar para inserir ou atualizar via programação num loop é algo muito demorado e inviável.
Das melhores solução mencionada estão:

1ª - Verificar se há suporte para o comando insert or update a ação de atualizar ou inserir fica com o SGDB em questão, isso vai diminuir em metade o tempo gasto
2ª - Trabalhar com comando Array DML fantástico e eficiente, pois muitas operações pode ser executada de uma unica vez, isso há uma ganho de performance sem igual.

Se não há possibilidade para a 1ª então recomenda que seja criado procedure stored, que faça o papel de verificar e inserir ou atualizar quando houver o tal registro desta forma voce passa o papel de verificar e atualizar ou inserir para o SGDB em questão.

Ainda não coloquei em pratica os comando Array DML apenas dei uma lida por alto, só será valido se estiver a usar componentes com suporte para tal, mais é uma baita solução.


bom é isso boa sorte.
Obrigado pela dica amigo.
_________________
Jogo seu smartphone? Acesse o link e confira.
https://play.google.com/store/apps/details?id=br.com.couldsys.rockdrum
https://play.google.com/store/apps/details?id=br.com.couldsys.drumsetfree
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
adriano_servitec
Colaborador
Colaborador


Registrado: Sexta-Feira, 30 de Janeiro de 2004
Mensagens: 17618

MensagemEnviada: Ter Ago 29, 2017 3:08 pm    Assunto: Responder com Citação

imex escreveu:
adriano_servitec escreveu:
Se o arquivo que esta vindo a ultima linha a onde tem o ID que vem do arquivo for igual ao campo id_web(tela local) e a data de alteracao que vem do arquivo for maior que a data de sincronismo da tabela local então é um update se não um insert e se nenhuma das condições for então significa que ambos estao iguais no arquivo e na tabela.

Pelo que entendi acho que essa verificação pode ser feita só uma vez na aplicação logo no início para ver se o looping deve ser executado ou não.


adriano_servitec escreveu:
Da pra fazer com merge no postgres?

Pelo que vi o Postgre tem o comando Merge. Com o Merge (ou o Insert or Update em outros bancos como o Firebird) é possível especificar algumas condições para ver se deve ser executado um Insert ou um Update. Segue abaixo um exemplo onde é verificado se o campo id_web passado por parâmetro existe ou não para executar um Update ou um Insert respectivamente:

Código:
MERGE INTO Grade g
USING (VALUES(:Pid_web as id_web,
              :Pid_cadastro as id_cadastro,
              :Pid_produto as id_produto,
              :Pid_grade_atributo_valor as id_grade_atributo_valor)) v
ON v.id_web = g.id_web
WHEN NOT MATCHED
  INSERT (id_web, id_cadastro, id_produto, id_grade_atributo_valor)
      VALUES(v.id_web, v.id_cadastro, v.id_produto, v.id_grade_atributo_valor)
WHEN MATCHED
  UPDATE SET
      id_cadastro = v.id_cadastro,
      id_produto = v.id_produto,
      id_grade_atributo_valor = v.id_grade_atributo_valor;


Espero que ajude


São 160 mil registros vindo do csv que preciso gravar. Por isso preciso verificar uma a um pra ver se tem na tabela (eu acho)

Se não como implemento este codigo acima passado?

Olha como é o arquivo que vem
Citação:
;62065;2067393;;39621;1609004933634;1609004933634;;1.000;0.000;0.000;0.000;95.20;0.00;238.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680795
;62065;2067460;;39621;1609004933638;1609004933638;;2.000;0.000;0.000;0.000;95.20;0.00;238.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680796
;62065;2067345;;39621;1708023033740;1708023033740;;2.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680797
;62065;2067339;;39621;1708023033738;1708023033738;;2.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680798
;62065;2067332;;39621;1708023033736;1708023033736;;1.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680799
;62065;2067300;;39621;1708023233640;1708023233640;;2.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680800
;62065;2067282;;39621;170105957342;170105957342;;2.000;0.000;0.000;0.000;119.20;0.00;298.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680801
;62065;2067325;;39621;1708023233644;1708023233644;;0.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680802
;62065;2067288;;39621;170105957344;170105957344;;1.000;0.000;0.000;0.000;119.20;0.00;298.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680803
;62065;2067359;;39621;1608035833534;1608035833534;;1.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680804
;62065;2067295;;39621;1708023233638;1708023233638;;1.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680805
;62065;2067279;;39621;170105957338;170105957338;;0.000;0.000;0.000;0.000;119.20;0.00;298.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680806
;62065;2067466;;39621;1609004933640;1609004933640;;1.000;0.000;0.000;0.000;95.20;0.00;238.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680807
;62065;2067349;;39621;1708023033742;1708023033742;;1.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680808
;62065;2067362;;39621;1608035833536;1608035833536;;0.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680809
;62065;2067276;;39621;170105957340;170105957340;;2.000;0.000;0.000;0.000;119.20;0.00;298.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680810
;62065;2067380;;39621;1608035833542;1608035833542;;1.000;0.000;0.000;0.000;107.20;0.00;268.00;0.00;0.00;0.000000000000000;150.000000000000000;0.000000000000000;0.000000000000000;1;;;680811


Isso é um pequeno parte de 160 mil reg.

Também não entendi este MERGE como é feito

Minha tabela tem esta estrutura
Código:
CREATE TABLE public.grade
(
  id_grade integer NOT NULL DEFAULT nextval('grade_id_grade_seq'::regclass),
  id_cadastro integer NOT NULL,
  id_produto integer NOT NULL,
  id_grade_atributo_valor character varying(255) DEFAULT NULL::character varying,
  id_usuario_alterou integer,
  codigo_barra_pai character(20) NOT NULL,
  codigo_barra character(20) DEFAULT NULL::bpchar,
  codigo_interno character(20) DEFAULT NULL::bpchar,
  qtd_atual numeric(10,3) DEFAULT 0.000,
  qtd_minima numeric(10,3) DEFAULT 0.000,
  qtd_locacao numeric(10,3) DEFAULT 0.000,
  qtd_locacao_locado numeric(10,3) DEFAULT 0.000,
  valor_custo numeric(10,2) DEFAULT NULL::numeric,
  valor_varejo_avista numeric(10,2) DEFAULT NULL::numeric,
  valor_varejo_aprazo numeric(10,2) DEFAULT NULL::numeric,
  valor_atacado_avista numeric(10,2) DEFAULT NULL::numeric,
  valor_atacado_aprazo numeric(10,2) DEFAULT NULL::numeric,
  porc_varejo_avista numeric(18,15) DEFAULT NULL::numeric,
  porc_varejo_aprazo numeric(30,20) DEFAULT NULL::numeric,
  porc_atacado_avista numeric(18,15) DEFAULT NULL::numeric,
  porc_atacado_aprazo numeric(18,15) DEFAULT NULL::numeric,
  ativo smallint DEFAULT '1'::smallint,
  alt_estoque character(1),
  editar character(1),
  excluir character(1),
  id_web integer,
  data_alteracao timestamp with time zone,
  data_sincronismo timestamp with time zone,
  CONSTRAINT grade_pkey PRIMARY KEY (id_grade)
)


Não entendi esta parte
Código:
USING (VALUES(:Pid_web as id_web,
              :Pid_cadastro as id_cadastro,
              :Pid_produto as id_produto,
              :Pid_grade_atributo_valor as id_grade_atributo_valor)) v
ON v.id_web = g.id_web


Outra coisa
Via código no delphi uso um fdQuery (firedac) neste codigo
Código:
MERGE INTO Grade g
USING (VALUES(:Pid_web as id_web,
              :Pid_cadastro as id_cadastro,
              :Pid_produto as id_produto,
              :Pid_grade_atributo_valor as id_grade_atributo_valor)) v
ON v.id_web = g.id_web
WHEN NOT MATCHED
  INSERT (id_web, id_cadastro, id_produto, id_grade_atributo_valor)
      VALUES(v.id_web, v.id_cadastro, v.id_produto, v.id_grade_atributo_valor)
WHEN MATCHED
  UPDATE SET
      id_cadastro = v.id_cadastro,
      id_produto = v.id_produto,
      id_grade_atributo_valor = v.id_grade_atributo_valor;


Passo os parametros via parambyname e um execute no final? Isso dentro do loop que le o csv?
_________________
Jogo seu smartphone? Acesse o link e confira.
https://play.google.com/store/apps/details?id=br.com.couldsys.rockdrum
https://play.google.com/store/apps/details?id=br.com.couldsys.drumsetfree


Editado pela última vez por adriano_servitec em Ter Ago 29, 2017 3:25 pm, num total de 1 vez
Voltar ao Topo
Ver o perfil de Usuários Enviar Mensagem Particular
Mostrar os tópicos anteriores:   
Novo Tópico   Responder Mensagem    ActiveDelphi - Índice do Fórum -> Delphi Todos os horários são GMT - 3 Horas
Ir à página 1, 2, 3, 4  Próximo
Página 1 de 4

 
Ir para:  
Enviar Mensagens Novas: Proibido.
Responder Tópicos Proibido
Editar Mensagens: Proibido.
Excluir Mensagens: Proibido.
Votar em Enquetes: Proibido.


Powered by phpBB © 2001, 2005 phpBB Group
Traduzido por: Suporte phpBB