Extending SetScope()

Extending SetScope()

Postby TimStone » Fri Oct 18, 2024 10:57 pm

I have a datafile that I use for "parts used on invoices".

For quick filterning, I use SetScope functions. ( top and bottom ). It uses the invoice number as the value for both. Thus when the invoice is open, only those parts used for that specific one will display in the xBrowse control. It all works perfectly.

Now I have a client who wants that same ability, but he wants to have the numbers "searchable" which would be accomplished by placing them in partnumber order.

Does anyone have a suggestion on how to do this without messing up the scope ?

Tim
Tim Stone
http://www.MasterLinkSoftware.com
http://www.autoshopwriter.com
timstone@masterlinksoftware.com
Using: FWH 23.10 with Harbour 3.2.0 / Microsoft Visual Studio Community 2022-24 32/64 bit
User avatar
TimStone
 
Posts: 2944
Joined: Fri Oct 07, 2005 1:45 pm
Location: Trabuco Canyon, CA USA

Re: Extending SetScope()

Postby paquitohm » Sat Oct 19, 2024 8:00 am

Hello,
In my case I use TSBrowse 6.0 with dbf table search.
When the user searches for articles, the program does an ordwildseek() and compiles the records (recnos()) into an array. Then oBrowse switches to "ARRAY" mode and displays the records of the collected array. The advantage of the process is that it is very fast. In addition, OrdWildSeek() does two searches, first a search for those that "start with" and then a search for those that "contain" so that first those that "start with" appear and then those that "contain". It would be very interesting if Mr. Nages added this feature for those who may be using xBrowse, which does not eliminate the possibility that the fwh developer can implement it more or less easily

[Original in spanish]
Hola,
En mi caso uso TSBrowse 6.0 con busqueda de tabla dbf.
Cuando el usuario hace una busqueda de artículos, el programa hace un ordwildseek() y recopila los registros (recnos()) en un array. Luego el oBrowse conmuta a modo "ARRAY" y muestra los registros del array recopilado. La ventaja del proceso es que es muy rapido. Ademas hace dos busquedas OrdWildSeek(), primero una busqueda para los que "empiezan por" y luego una busqueda para los que "contienen" de manera que primero aparecen los que "empiezan por" y despues los que "contienen". Interesantísimo sería que Mr. Nages añadiera esta característica para los que puedan estar usando xBrowse, lo cual no quita la posibilidad de que el desarrollador fwh lo pueda implementar más o menos facilmente
paquitohm
 
Posts: 266
Joined: Fri Jan 14, 2022 8:37 am

Re: Extending SetScope()

Postby karinha » Sat Oct 19, 2024 12:46 pm

João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
User avatar
karinha
 
Posts: 7832
Joined: Tue Dec 20, 2005 7:36 pm
Location: São Paulo - Brasil

Re: Extending SetScope()

Postby nageswaragunupudi » Sat Oct 19, 2024 3:06 pm

TimStone wrote:I have a datafile that I use for "parts used on invoices".

For quick filterning, I use SetScope functions. ( top and bottom ). It uses the invoice number as the value for both. Thus when the invoice is open, only those parts used for that specific one will display in the xBrowse control. It all works perfectly.

Now I have a client who wants that same ability, but he wants to have the numbers "searchable" which would be accomplished by placing them in partnumber order.

Does anyone have a suggestion on how to do this without messing up the scope ?

Tim


When we are using SetScope(), we can not change the index order. That is our constraint now.
There are quite a few alternatives, including reading into an array, etc. but they reduce overall speeds and also require major changes.
We need to look for simpler solutions without much change in our existing software.

1. Use Filter instead of Scope:

I am sure you will not like this idea at all.
Most of us are brain-washed to believe that filters are very very slow.
Not so.
Situation changed 3 decades back when FoxPro introduced Rushmore technology and our present DBFCDX uses similar technology to optimize filters.
Since we already have and index on the field "INVOICE",
Code: Select all  Expand view  RUN
INCOICE="ABCDEF"

is highly optimized.
That means we can use filters instead of Scopes to limit visibility of parts table pertaining to an invoice using filters also.
Once we use filters instead of scopes, we can change the index order of the parts browse to any indexed column and do seeks.

Note: Filters are still a bit slower than Scopes though the difference in speeds may not be perceptible.

2. Continue using scopes

(a) Use compound index "INVOICE+PARTNUMBER" instead of "INVOICE"
Still SetScope on invoice number works the same way even with this compound index.
At the same time, within the browse partnumbers appear in the ascending order.
When you want to search a part number, seek "INCVOICE" + "PARTNUMBER". We can do incremental search also.

(b) Continue your same program as it is. Instead of SEEK, use LOCATE to search the part number. I can assure that this also will be fast enough

You may consider options 2(b), 2(a), 1 in that order.

Please feel free to ask if you like us to support you with a sample program in any of these alternatives.
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10646
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: Extending SetScope()

Postby Marc Venken » Sat Oct 19, 2024 3:27 pm

Several members had filter, scopes etc. questions last period, so samples of optimised filters are VERY welcome.
Allmost all actions in my program are filter based.
Marc Venken
Using: FWH 23.04 with Harbour
User avatar
Marc Venken
 
Posts: 1439
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: Extending SetScope()

Postby karinha » Sat Oct 19, 2024 4:38 pm

Marc, how do you make your filters? I always prefer using these commands:

Marc, ¿cómo haces tus filtros? Siempre prefiero usar estos comandos:

Code: Select all  Expand view  RUN

// C:\FWH\SAMPLES\SETSCOPE.PRG

#include "FiveWin.ch"

ANNOUNCE RDDSYS
REQUEST OrdKeyNo, OrdKeyCount, OrdCreate, OrdKeyGoto
REQUEST DBFCDX, DBFFPT

FUNCTION Main()

   FIELD AGE

   LOCAL cAlias, aGeIni := 20, aGeFin := 30

   RDDSETDEFAULT("DBFCDX")
   RDDREGISTER( "DBFCDX", 1 ) // RDT_FULL

   // The following example illustrates the SET SCOPE command:
   CLOSE DATABASE

   USE CUSTOMER NEW

   INDEX ON AGE TO CUSTOMER

   // Only part numbers between 20 and 30 will be used
   SET SCOPE TO 20, 30  // AGES: MIN 20 MAX 30

   GO TOP

   XBROWSE()

   SET SCOPE TO

   cAlias := ALIAS()

   // Using INDEX ON... MEMORY / TEMPORARY
   // Only part numbers between 20 and 30 will be used
   INDEX ON AGE TAG 02 TO MARCTEMP FOR ( .NOT. EOF() ) .AND. ;
         ( cAlias )->AGE >= aGeIni                     .AND. ;
         ( cAlias )->AGE <= aGeFin MEMORY // TEMPORARY

   GO TOP

   XBROWSE()

   OrdDestroy( "MARCTEMP" )

   CLOSE DATABASE

RETURN NIL

/*
// Seealso

// ORDSCOPE(), SET SCOPEBOTTOM, SET SCOPETOP
*/


// FIN / END - kapiabafw@gmail.com
 


Regards, saludos.
João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
User avatar
karinha
 
Posts: 7832
Joined: Tue Dec 20, 2005 7:36 pm
Location: São Paulo - Brasil

Re: Extending SetScope()

Postby Marc Venken » Sat Oct 19, 2024 7:44 pm

I use several.... because I saw the samples on the forum. therefore that the explenation of Mr. Rao could give me the final tip for the best.

Thinks I active use : (code like they are)

oBrw[1]:bChange := { || orderfilter("factart","factart",factinfo->document),orderfilter("detail","factart",factinfo->document),oBrwFol2[1]:gotop(),oBrwFol2[1]:refresh() }

Code: Select all  Expand view  RUN

function orderfilter(cAlias,cTag,cStart)
   local cOld_alias:=Alias(), NTag:= &cOld_alias->(indexord())
   default cStart:=""
   select &cAlias
   set order to tag &cTag
   if !empty(cTag)
      set scope to alltrim(cStart)
   endif
   &cAlias->(dbgotop())
   select &cOld_alias
   &cOld_alias->(dbsetorder(nTag))
return NIL

 


or this

Code: Select all  Expand view  RUN

  netopen("brwsetup","Code","TempXb")
  select TempXB
  set filter to brwnaam = cData
  tempXB->(dbgotop())
  hBrw:= FW_RecToHash()  // Start using Hash for all replaces below

 



:bBarGetAction := {|| ( oBrw:cAlias )->( MARC_SETFILTER( oBrw ) ) } // this for show the bitmap on the get and associated a action

Code: Select all  Expand view  RUN

FUNCTION MARC_SETFILTER( oBrw ) // My filter for Xbrowse heather gets.

   LOCAL cFilter := ""
   LOCAL n, oCol, uVal, cType, cVal1, cVal2, nGevonden
   LOCAL nZoekKnop, cExprt
   FOR n := 1 TO Len( oBrw:aCols )
      oCol  := oBrw:aCols[ n ]
      IF ! Empty( uVal := oCol:uBarGetVal )
         IF !Empty( cFilter )
            cFilter  += " .AND. "
         ENDIF
         cType    := ValType( uVal )
         if cType = "C"
           nGevonden = at("++",uVal) //  used because I want to look for 2 items in one get
         endif
         if cType = "C"
           nZoekKnop = at("²",uVal)  // used because I set a function key to this to start the search, so no click needed
         endif

         DO CASE
          CASE cType == 'C' .and. nZoekKnop > 0  
            uVal     := Upper( AllTrim( uVal ) )
            cVal1 = substr(uVal,1,nZoekknop-2)
            cFilter += '"' + cVal1 + '" $ UPPER( ' + oCol:CExpr + " )"
          CASE cType == 'C' .and. nGevonden > 0
            uVal     := Upper( AllTrim( uVal ) )
            cVal1 = substr(uVal,1,nGevonden-1)
            cVal2 = substr(uVal,nGevonden+2)

            cFilter += '"' + cVal1 + '" $ UPPER( ' + oCol:CExpr + " )"
            cFilter += " .AND. "
            cFilter += '"' + cVal2 + '" $ UPPER( ' + oCol:CExpr + " )"
         CASE cType == 'C'
            uVal     := Upper( AllTrim( uVal ) )
            cFilter += '"' + uVal + '" $ UPPER( ' + oCol:CExpr + " )"
         CASE cType == 'D'
            cFilter  += oCol:cExpr + " = " + ( uVal )
         OTHERWISE
            cFilter  += oCol:cExpr + " == " + cValToChar( uVal )
         ENDCASE
      ENDIF

   NEXT

   IF Empty( cFilter )

      IF ! Empty( dbFilter() )
         dbClearFilter()
         oBrw:Refresh()
      ENDIF

   ELSE

      IF !( dbFilter() == cFilter )
         oClp:SetText(cFilter) //  used because I generate filters on the fly with Xbrowse, copy paste into a lookup table for later use
         if !empty(alias())
           SET FILTER TO &cFilter
           oClp:SetText(cFilter)
           GO TOP
         else
           msginfo("Error.... Geen Alias beschikbaar")
         endif

         oBrw:Refresh()
      ENDIF

   ENDIF
   oBrw:maketotals()
   oBrw:SetFocus()

RETURN NIL
 


and this

oBrw[2]:bChange := { || Scope("factinfo","document","factart","factart"),oBrw22:refresh() }

Code: Select all  Expand view  RUN

function Scope(cParent,cData,cChild,cChildTag,cFoto)
  LOCAL cZoekdata
  LOCAL aScope1, aScope2
  DEFAULT cFoto:=""

  cZoekdata = cData
  if left(cZoekdata,1) = "#" //  breakpoint in order to look for 2 items in one field
    cZoekdata:= substr(cZoekdata,2)
  else
    cZoekdata:= upper( (cParent)->&cData)
  endif


  if cZoekdata = sys_scope
     return NIL
  endif
  sys_Scope = cZoekdata

  (cChild)->(dbsetorder(cChildTag))

  (cChild)->(ORDSCOPE(0, "" ) )
  (cChild)->(ORDSCOPE(1, "" ) )

  (cChild)->( ORDSCOPE(0, cZoekData ) )
  (cChild)->(ORDSCOPE(1, cZoekData ) )
  (cChild)->(DBGOTOP())

   //aScope := FW_DbfToArray( "JAN,FEB,MAR,APR,MAY", { || FIELD->REGION = cRegion } )
   //aScope1 := (cChild)->( FW_DbfToArray() )

  do case
    case upper(cChild) = "NOFOTOART"
      nofotoart->(dbsetorder("ID"))
      nofotoart->(ORDSCOPE(0, "" ) )
      nofotoart->(ORDSCOPE(1, "" ) )
      nofotoart->( ORDSCOPE(0, cZoekData ) )
      nofotoart->(ORDSCOPE(1, cZoekData ) )
      nofotoart->(DBGOTOP())
      aScope2 := (cChild)->( FW_DbfToArray() )
      ACopy(aScope1,aScope2)
      xbrowser(aScope2)

    case cFoto = "NOFOTO"
       Sys_wnd_foto = getorgfoto(nofoto->orgfoto)
       oSys_image:refresh()
  endcase
Return NIL

 
Marc Venken
Using: FWH 23.04 with Harbour
User avatar
Marc Venken
 
Posts: 1439
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: Extending SetScope()

Postby Marc Venken » Sat Oct 19, 2024 7:49 pm

The magic lies in the Optimized filter with CDX, but when is it optimized ?

By setting the indexes ?
You see option 2b of Mr. Rao ? Using Locate ? didn't know it )))

I think if more members request the samples from Mr. Rao he will help us
Marc Venken
Using: FWH 23.04 with Harbour
User avatar
Marc Venken
 
Posts: 1439
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: Extending SetScope()

Postby TimStone » Sat Oct 19, 2024 11:26 pm

Thank you.

I decided to use 2(a) because having them in partnumber order is sufficient at this time. However, I will happily explore the FILTER option.

I should mention that I'm using database objects, and though I tried the filter first, it wasn't working. I'm sure it was how I implemented it.

I, too, would appreciate some examples of these. Links to previous references on this forum would be fine.

Tim
Tim Stone
http://www.MasterLinkSoftware.com
http://www.autoshopwriter.com
timstone@masterlinksoftware.com
Using: FWH 23.10 with Harbour 3.2.0 / Microsoft Visual Studio Community 2022-24 32/64 bit
User avatar
TimStone
 
Posts: 2944
Joined: Fri Oct 07, 2005 1:45 pm
Location: Trabuco Canyon, CA USA


Re: Extending SetScope()

Postby karinha » Sun Oct 20, 2024 12:03 pm

Marc, SET FILTER TO &cFilter, doesn't this make the FILTER extremely SLOW? Some clients of the company I work for have giant databases, and using SET FILTER TO was driving them crazy, it took up to 30 minutes to make a simple FILTER. I changed everything to INDEX ON...MEMORY/TEMPORARY.

Marc, SET FILTER TO &cFilter, ¿esto no hace que el FILTRO sea extremadamente LENTO? Algunos clientes de la empresa para la que trabajo tienen bases de datos gigantes, y usar SET FILTER TO los estaba volviendo locos, les llevó hasta 30 minutos hacer un FILTRO simple. Cambié todo a ÍNDICE EN...MEMORIA/TEMPORAL.

Gracias, tks.

Regards, saludos.
João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
User avatar
karinha
 
Posts: 7832
Joined: Tue Dec 20, 2005 7:36 pm
Location: São Paulo - Brasil

Re: Extending SetScope()

Postby Marc Venken » Sun Oct 20, 2024 1:08 pm

I have a dbf with 380.000 records, 32 fields and 7 tags. (242 Megabite)

the filter look like :

"WIC" $ UPPER( TAG ) .AND. "POLO" $ UPPER( NAAM ) .AND. "WHITE" $ UPPER( KLEUR )

This filter is build with the above function Marc_Setfilter using Xbrowse header gets.

The active tag =

upper(reflev)+upper(kleur)+upper(size)

If I try 10 filtercombinations the results are between 4-20 secs, not knowing why slower some times.

Thats why Mr. Rao's presentation will be great.
Marc Venken
Using: FWH 23.04 with Harbour
User avatar
Marc Venken
 
Posts: 1439
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: Extending SetScope()

Postby Marc Venken » Sun Oct 20, 2024 1:15 pm

karinha wrote:Marc, I changed everything to INDEX ON...MEMORY/TEMPORARY.



This I want to try .... Just made a tmp index once in a while but as you confirm, it is fast.

Have you acode snipped where you use Xbrowse Header gets and use temp index instead of filter.
You would make

local ...
Field Tag, Naam, Kleur

Filter =
"WIC" $ UPPER( TAG ) .AND. "POLO" $ UPPER( NAAM ) .AND. "WHITE" $ UPPER( KLEUR )
Index will be like
index on upper(TAG)+upper(NAAM)+upper(KLEUR) tmp (sample, not the correct syntax)

cData = upper(Tag)+upper(naam)+upper(kleur)
ean->(dbseek(cData))

this is what you mean ?
Marc Venken
Using: FWH 23.04 with Harbour
User avatar
Marc Venken
 
Posts: 1439
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Re: Extending SetScope()

Postby Enrico Maria Giordano » Sun Oct 20, 2024 1:24 pm

Marc Venken wrote:upper(reflev)+upper(kleur)+upper(size)


I suggest this optimization:

Code: Select all  Expand view  RUN
upper(reflev+kleur+size)
User avatar
Enrico Maria Giordano
 
Posts: 8718
Joined: Thu Oct 06, 2005 8:17 pm
Location: Roma - Italia

Re: Extending SetScope()

Postby Marc Venken » Sun Oct 20, 2024 8:27 pm

Enrico Maria Giordano wrote:
Marc Venken wrote:upper(reflev)+upper(kleur)+upper(size)


I suggest this optimization:

Code: Select all  Expand view  RUN
upper(reflev+kleur+size)


I see that the index will be faster since upper is from 3 to 1, but is it also nessesary to change how the filter will be created ?

Current filter :

"WIC" $ UPPER( TAG ) .AND. "POLO" $ UPPER( NAAM ) .AND. "WHITE" $ UPPER( KLEUR )
Marc Venken
Using: FWH 23.04 with Harbour
User avatar
Marc Venken
 
Posts: 1439
Joined: Tue Jun 14, 2016 7:51 am
Location: Belgium

Next

Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: Willi Quintana and 41 guests