Página 1 de 3

erro no set filter

Enviado: 20 Fev 2013 01:09
por cjp
Pessoal,

Estou tendo um erro estranho no meu programa compilado no Harbour: o set filter não está funcionando direito.

Estou usando assim:

Código: Selecionar todos

                            set filter to ac1$acao
No Xharbour funcionava perfeitamente.

Mas agora, no Harbour, ele só está filtrando o primeiro registro da base que corresponde ao filtro, embora haja vários.

Isso acontece também em outros pontos do programa onde uso o set filter.

Alguém sabe me dizer por que? Estou fazendo algum errado?

erro no set filter

Enviado: 20 Fev 2013 01:47
por rochinha
Amiguinho,

Meu exemplo:

Código: Selecionar todos

function FiltraNome( cArea,cOrdem,cQueNome )
   cBRFiltro := "!DELETED()"
   dbSelectArea( cArea )    // Seleciona area requerida
   OrdSetFocus( cOrdem )  // Sleciona ordem requerida
   dbSetFilter( {|| .t.}, "" )  // Libera filtros na area
   cBRFiltro := cBRFiltro + " .and. clientes->nome=" + cQueNome
   dbSetFilter( {|| &cBRFiltro. }, &cBRFiltro. )
   dbGoTop()

erro no set filter

Enviado: 20 Fev 2013 02:16
por alxsts
Olá!

Não consegue usar OrdScope()?

erro no set filter

Enviado: 20 Fev 2013 12:33
por cjp
Não conheço a OrdScope() nem a Dbsetfilter(). Não achei essas funções no NG do velho Clipper.

Poderiam, por favor, me dar melhor descrição dos seus argumentos e forma de uso exato?

Mas existe algum problema em usar set filter?

Agradeço.

erro no set filter

Enviado: 20 Fev 2013 12:51
por alxsts
Olá!

Você postou na seção Harbour. Está usando Clipper?

OrdScope() só funciona em Clipper 5.3, Harbour e xHarbour. Alem disso, você tem que estar usando o RDD DBFCDX.

Segue um exemplo. No Ord.ch as constantes TOPSCOPE e BOTTOMSCOPE tem os valores 1 e 2, respectivamente Top e Bottom Scope definem uma faixa de chaves de índice que serão consideradas. No exemplo abaixo, somente pessoas com sobrenomes iniciados com as letras entre "E" e "K", incluindo estas,serão mostrados no Browse():

Código: Selecionar todos

// The example demonstrates evaluation of scope code blocks while a
// database is browsed. Although the code blocks return constant values,
// they could return the result of a function call as well.

   #include "Ord.ch"

   PROCEDURE Main
      USE Customer
      INDEX ON Upper(LastName+Firstname) TO Cust01

      OrdScope( TOPSCOPE   , {|| Tone(1000), "E" } )

      OrdScope( BOTTOMSCOPE, {|| Tone(500), "K" } )

      Browse()
   RETURN
Segue um exemplo de DbSetFilter(), embora eu não a recomende:

Código: Selecionar todos

// The example demonstrates the effect of a filter condition

   PROCEDURE Main
      USE Customer
      INDEX ON Upper(LastName) TO Cust01

      GO TOP
      ? Recno(), Lastname              // result: 28 Abbey

      DbSetFilter( {|| Upper(LastName) > "L" }, ;
                      'Upper(LastName) > "L"'   )

      GO TOP
      ? Recno(), Lastname              // result: 182 MacDonald

      ? DbFilter()                     // result: Upper(LastName) > "L"

      CLOSE Customer
   RETURN

erro no set filter

Enviado: 20 Fev 2013 17:10
por cjp
Eu estou usando o Harbour.

Só mencionei o Clipper porque procurei essas funções no NG do Clipper, mas não achei. Como não tenho um NG (ou algo semelhante) do Harbour, quando se trata de função que já tinha no Clipper, tento consultar o NG do Clipper.

Não entendi bem como funciona a OrdScope(). Parece que ela não faz filtro, estou correto? Tentei fazer assim:

Código: Selecionar todos

#include "Ord.ch"

   INDEX ON acao TO Cust01

   OrdScope( TOPSCOPE , {|| Tone(1000), ac1$acao } )

   OrdScope( BOTTOMSCOPE, {|| Tone(500), ac1$acao } )

   Browse()
 
Mas não filtrou.

Quanto à DbSetfilter(), está dando o mesmo problema que dava no set filter, ou seja, só aparece a primeira ocorrência do filtro. E dbfilter() não está retornando nada. Estou fazendo assim:

Código: Selecionar todos

   DbSetFilter( {|| ac1$acao })


   GO TOP
cls
   ? DbFilter()          // result: Upper(LastName) > "L"

Será que estou fazendo algo errado?

erro no set filter

Enviado: 20 Fev 2013 19:08
por alxsts
Olá!

Qual o conteúdo de ac1$acao? Tem que ser um valor do mesmo tipo da chave de índice e que possa existir no índice.

erro no set filter

Enviado: 20 Fev 2013 19:53
por rochinha
Amiguinho,

O dbSetFilter precisa de dois parametros:

Código: Selecionar todos

dbSetFilter( <codeblock>, <string> )
Teste:
DbSetFilter( )

Código: Selecionar todos

? cSetFilter := ac1$acao
dbSetFilter( {|| &cSetFilter. }, &cSetFilter. )
Agora mostre-nos trecho do código que cria sua variável ac1$acao. Já estamos tendo de adivinhar pra dar resposta.

Coloque o trecho acima no seu programa e nos diga qual foi o conteudo mostrado na linha ? cSetFilter := ac1$acao.

Se a filtragem não esta resultado em registros é porque nada que valha a filtragem está sendo passado para o comando.

E também já estou velho, nem lembro o porque do uso que voce faz de $, em {|| ac1$acao }.

Pelo que entendi:

Voce tem uma variável chamada ACL e está criticando o conteúdo do campo acao.

Pois bem:

Voce não terá filtragem nenhuma porque, se a variável acl retornar falso caso não seja encontrada no campo acao.

Para usar o operador $ voce estará perguntando: procure ACL dentro de ACAO

O que esta ocorrendo é que o comando de filtragem está recebendo somente, .T. ou .F. puros, ou seja:

Código: Selecionar todos

dbSetFilter( .t., ".t." )
ou:

Código: Selecionar todos

dbSetFilter( .f., ".f." )
Isto não irá fazer nenhum efeito.

Voce deve passar uma expressão que valha a pena, exemplo:

Voce que pesquisar por um código dentro de um campo e filtrar tudo relativo:

Código: Selecionar todos

nNumero  := "123"
cSetFilter := "TABELA->CODIGO = " + strZero( nNumero, 5 )
dbSetFilter( {|| &cSetFilter. }, &cSetFilter. )
Ou:

Código: Selecionar todos

cNome  := "ROCHA"
cSetFilter := "upper(TABELA->NOME) = " + upper( cNome )
dbSetFilter( {|| &cSetFilter. }, &cSetFilter. )

erro no set filter

Enviado: 21 Fev 2013 01:31
por cjp
Cara, agradeço muito tua tentativa em ajudar, mas eu ainda não consegui entender como usar essa dbsetfilter().

Minha função original, com set filter, estava assim:

Código: Selecionar todos

                 index on substr(acao,1,4) to inddt for !empty(acao) unique
                 go bottom
                 go top
                 clear
                 @ 3,1 say "Escolha as ações:"
                 private v1[1]
                 v1[1]="Acao"
                 do while .t.
                    dbedit(5,1,22,20,v1)
                    if lastkey()=27
                       exit
                    endif
                    if deleted()
					   flock()
                       recall
                    else
					   flock()
                       dele
                    endif
                 enddo
			     unlock
                 ac1=space(20)
                 ac2=space(20)
                 ac3=space(20)
                 ac4=space(20)
                 ac5=space(20)
                 go top
                 locate for deleted()
                 if found()
                    ac1=substr(acao,1,4)
                    if "Adia"$ac1
                       ac1="Adia"
                    endif
                    continue
                    if found()
                       ac2=substr(acao,1,4)
                       continue
                       if found()
                          ac3=substr(acao,1,4)
                          continue
                          if found()
                             ac4=substr(acao,1,4)
                             continue
                             if found()
                                ac5=substr(acao,1,4)
                                continue
                                if found()
                                   tone(261.7,3)
                                   @ maxrow(),5 say "Erro: pesquisa máxima de 5 ações ultrapassada"
                                   inkey(5)
                                endif
                             endif
                         endif
                       endif
                    endif
                    if usebase(athor)=.t.
					   flbs()
                       recall all
					   unlock
					endif
                    do case
                       case !empty(ac5)
                            set filter to ac1$acao .or. ac2$acao .or. ac3$acao .or. ac4$acao .or. ac5$acao //.or. empty(hora)
                       case !empty(ac4)
                            set filter to ac1$acao .or. ac2$acao .or. ac3$acao .or. ac4$acao //.or. empty(hora)
                       case !empty(ac3)
                            set filter to ac1$acao .or. ac2$acao .or. ac3$acao //.or. empty(hora)
                       case !empty(ac2)
                            set filter to ac1$acao .or. ac2$acao //.or. empty(hora)
                       otherwise
                            set filter to ac1$acao //.or. empty(hora)
                    endcase
                 else
                    use
                    return
                 endif
Portanto, as variáveis ac1, ac2, ac3, ac4 e ac5 são variáveis texto que correspondem ao campo acao, da base.

O objetivo é listar os registros da base cujo campo acao correspondem às variáveis escolhidas pelo usuário.

Com set filter sempre funcionou perfeitamente, até eu mudar do xHarbour para o Harbour. Ainda não entendi porque não funciona mais. O set filter não funciona no Harbour? E não tem nada simples que lhe equivalha?

Testei os teus exemplos, mas não funcionou. Embora eu não saiba se fiz corretamente. Testei assim:

Código: Selecionar todos

cSetFilter := acao + ac1
dbSetFilter( {|| &cSetFilter. }, &cSetFilter. )
Agradeço a ajuda.

erro no set filter

Enviado: 21 Fev 2013 03:20
por rochinha
Amiguinho,

Se me clareou as idéias tenho pra mim que voce esta tentando simular o CTRL+Click do mouse que damos quando queremos marcar itens aleatórios em um browse.

Pelo que vi voce deleta os registros que deseja depois filtrar, mas se o seu aplicativo contivar a diretiva SET DELETE OFF os registros se tornarão invisiveis e quando voce tentar filtrar nada será mostrado.

Uma saida para isto possa ser um campo extra, tipo um flag, que se marcado poderá permitir a filtragem por ele.

Mas se voce deseja filtrar a tabela pelo campo desejado e que contenha até 5 parametros voce pode passar o conteudo das variáveis assim:

Código: Selecionar todos

Set Delete Off

cSetFilter := [!deleted()]

cSetFilter := cSetFilter + iif( !empty( AC1, [ .OR. TABELA->ACAO $ "] + alltrim( AC1 ) + ["], [] )
cSetFilter := cSetFilter + iif( !empty( AC2, [ .OR. TABELA->ACAO $ "] + alltrim( AC2 ) + ["], [] )
cSetFilter := cSetFilter + iif( !empty( AC3, [ .OR. TABELA->ACAO $ "] + alltrim( AC3 ) + ["], [] )
cSetFilter := cSetFilter + iif( !empty( AC4, [ .OR. TABELA->ACAO $ "] + alltrim( AC4 ) + ["], [] )
cSetFilter := cSetFilter + iif( !empty( AC5, [ .OR. TABELA->ACAO $ "] + alltrim( AC5 ) + ["], [] )

? "Filtro: ", cSetFilter

dbSetFilter( {|| &cSetFilter. }, &cSetFilter. )
Compile este trecho passando aleatóriamente parametros para AC1, AC2,..., AC5 e veja como a string de filtragem é montada.

erro no set filter

Enviado: 21 Fev 2013 11:22
por cjp
Ainda não funcionou, meu amigo.

Na verdade, na primeira parte, eu uso sim o deleted para marcar na base os campos que eu quero filtrar, tomando-os para as variáveis ac1, ac2...ac5.

Mas depois eu dou um recall all. Portanto, daí em diante, o deleted não é mais usado.

A partir daí, a questão é apenas filtrar os campos da base que contenham os conteúdos das variáveis ac1... ac5.

Se eu entendi o que vc fez, o teu filtro estaria considerando o deleted, o que não é o caso. E também está invertido, filtrando pelo campo incluído na variável ([ .OR. TABELA->ACAO $ "] + alltrim( AC1 )), quando deveria ser a variável incluída no campo (ac1 $ TABELA->ACAO). Por isso não filtrou corretamente.

Tentei inverter, mas não funcionou. Na verdade eu ainda não entendi bem a lógica de funcionamento dessa função, por isso não estou conseguindo fazer como deveria.

Por favor, preciso novamente da sua ajuda.

erro no set filter

Enviado: 21 Fev 2013 13:00
por rochinha
Amiguinho

Realmente eu inverti as bolas o correto esta abaixo:

Código: Selecionar todos

AC1 := "scuba"
AC2 := "blue"
AC3 := ""
AC4 := ""
AC5 := ""

use CUSTOMER shared

Set Delete Off

cSetFilter := [!deleted()]

cSetFilter := cSetFilter + iif( !empty( AC1), [ .AND. ("] + alltrim( upper(AC1)  ) + [" $ upper(CUSTOMER->company)], [] )
cSetFilter := cSetFilter + iif( !empty( AC2),   [ .OR. "] + alltrim( upper(AC2)  ) + [" $ upper(CUSTOMER->company)], [] )
cSetFilter := cSetFilter + iif( !empty( AC3),   [ .OR. "] + alltrim( upper(AC3)  ) + [" $ upper(CUSTOMER->company)], [] )
cSetFilter := cSetFilter + iif( !empty( AC4),   [ .OR. "] + alltrim( upper(AC4)  ) + [" $ upper(CUSTOMER->company)], [] )
cSetFilter := cSetFilter + iif( !empty( AC5),   [ .OR. "] + alltrim( upper(AC5)  ) + [" $ upper(CUSTOMER->company)], [] )
cSetFilter := cSetFilter + [)]

? "Filtro: ", cSetFilter

dbSelectArea( "CUSTOMER" )

dbSetFilter( {|| &cSetFilter. }, &cSetFilter. )
dbGoTop()

Browse()
Neste caso o Set Delete Off mostra até os deletados.

Faça o download do arquivo customer.dbf.zip(elimine o .ZIP), compile o trecho acima e rode. Ou teste com custtest.exe.

erro no set filter

Enviado: 21 Fev 2013 23:04
por cjp
Testando com o .exe e o .dbf que vc mandou, funcionou perfeitamente.

Mas, quando transformo para usar no programa, dá o seguinte erro:

Código: Selecionar todos

Error BASE/1449  Erro de sintaxe: &
A linha onde está dando o erro é esta:

Código: Selecionar todos

dbSetFilter( {|| &cSetFilter. }, &cSetFilter. )
Estou colocando assim no meu programa:

Código: Selecionar todos

Set Delete Off

cSetFilter := [!deleted()]

cSetFilter := cSetFilter + iif( !empty( AC1), [ .AND. ("] + alltrim( upper(AC1) ) + [" $ upper(acao)], [] )
cls
? "Filtro: ", cSetFilter
wait ""

dbSetFilter( {|| &cSetFilter. }, &cSetFilter. )
Ainda estou fazendo errado?

erro no set filter

Enviado: 22 Fev 2013 02:55
por rochinha
Amiguinho,

Nem precisarei testar para saber que voce deixou de fora um parentesis. Como prova valendo 10, deixo voce descobrir.

Testes só dão resultados por prova e erro, ou, prova e acerto.

erro no set filter

Enviado: 22 Fev 2013 09:48
por asimoes
Nesse caso eu trabalharia com indices temporários e com ordscope que é bem mais rápido que set filter ou dbsetfilter