1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
  2. Anuncie Aqui
    Anuncie aqui você Também: fdantas@4each.com.br

duvia pra criar query.

Discussão em 'Progress 4GL' iniciado por LeandroSantos, Setembro 20, 2010.

  1. LeandroSantos

    LeandroSantos Membro Participativo

    Tenho 2 tabelas com um campo comum "id-conta"

    na tabela A tenho os valores:
    1,2,3,4,5,6,7,8,9,10
    na Tabela B tenho:
    1,4,5,6,9,10

    Como fasso para abrir a query e me mostrar apena os registro da tabela A que não existe na Tabela B.
    quero que me mostre a tabela A apenas os registros com valores:
    2,3,7,8

    Hoje estou fazendo assim:
    Dou um for each na tabela A e buscando na tabela B se não encontrar crio uma temp-table e uso essa temp-table pra cria a query, mas como a quantidade de registro é grande fica muito demorado o processo.

    Tem outra maneira de fazer isso, sem utilizar temp-table?
  2. Rogerio

    Rogerio Moderator Moderador Equipe de Suporte

    Posta o seu código de hoje, dai dá pra ter uma base melhor e poder te ajudar.
  3. LeandroSantos

    LeandroSantos Membro Participativo

    Hoje crio uma temp-table e populo ela:
    Código:
    def temp-table tt_contas
        field id-conta like fx_contas.id-conta.
    
    for each fx_contas no-lock.
        find first fx_estrutura no-lock
            where  fx_estrutura.codest   = fx_contas.codest
            and    fx_estrutura.id-conta = fx_contas.id-conta
            no-error.
        if not available fx_estrutura
        then do:
            create tt_contas.
            tt_contas.id-conta = fx_contas.id-conta.
        end.
    end.
    
    e minha query ficou assim:
    Código:
    def var qhfx_contas as handle no-undo.
    def var vtemp as char no-undo.
    create query qhfx_contas.
    qhfx_contas:set-buffers ( buffer fx_contas:handle, buffer tt_contas:handle).
    vtemp = " for each fx_contas no-lock"
          + "    where fx_contas.codest = " + quoter(clic1)
          + "  , first tt_contas no-lock"
          + "    where tt_contas.id-conta = fx_contas.id-conta".
    qhfx_contas:query-prepare(vtemp).
    qhfx_contas:query-open.
    
    O problema é na hora de popular a temp-table, por ter um grande numero de registros.
  4. MFerreira

    MFerreira Membro Participativo

    Boa Tarde amigo.

    Interessante sua necessidade.

    Algo que pode lhe ajudar é no momento de criar a temp-table, no for each, colocar um can-find ao invés de dar um for each: find. (Assim você evita trazer o registro da tabela 2 para buffer só para criar uma temp-table) o seu for each também pode colocar uma cláusula fields, já que você colocará poucos campos na tt
    Ex:
    for each <tabela> where not can-find(first <tabela2> where <tabela2>.<campo> = <tabela>.<campo>):
    create....
    end.

    Outra coisa que você pode tentar fazer é abrir a query para todos os registros e no momento de navegar, dar um next para os registros que você não queira.
    Este caso não fiz um teste, mas aí você evitaria dar um for each só pra criar uma temp-table com os registros que você quer. Dependendo do número de registros também, este exemplo poder ser mais rápido.
    do while not query:query-off-end:
    if can-find(first <tabela2> no-lock where <tabela2>.campo = <buffer-query>.<campo>) then query:get-next().
    end.

    Se alguém tiver algum outro exemplo também quero, pois fiquei interessado nesta situação.
  5. LeandroSantos

    LeandroSantos Membro Participativo

    Com esta sua dica melhorou acho que uns 20% o tempo, mas precisaria melhor mais.

    Não tenho como fazer isso porque preciso mostrar os dados em um browse.

    Obrigado!
  6. kirchner

    kirchner Membro Participativo Moderador

    Leandro,

    Isso que você quer fazer chama-se, na literatura, de "Left Anti Semi Join". É uma operação que, de 2 entradas, retorna dados apenas da primeira desde que não exista um correspondente na segunda.

    A melhor forma de executar esta operação depende dos volumes envolvidos. O SQL Server, por exemplo, consegue executar como um Loop Join, um Merge Join ou um Hash Join. E ele escolhe a melhor maneira em tempo de execução, dependendo da quantidade de dados.

    A solução que você usou é boa para pequenos volumes. O Hash Join tem um custo inicial bastante alto, mas o custo por registro processado é baixíssimo. Por isto em uma execução grande este método é excelente.

    O problema é que no Progress você tem que dizer exatamente COMO fazer, mesmo antes de ter os dados disponíveis. O Progress é procedural, você tem que codificar tudo. Isso é bem diferente de uma linguagem SQL que você diz O QUE você quer, e o banco executa como for mais rápido.

    Mas se você sabe que o volume previsto é bem grande, e tiver um índice nas duas tabelas no campo de junção, um algorítimo estilo MERGE seria ideal. Daí você faz apenas 1 leitura em cada uma das tabelas. Acho que é o melhor caso.
    Implementar HASH no Progress eu suponho que seja bastante trabalhoso....

Compartilhe esta Página