Queries and Can-Find

Afternoon fellows,

I'm having a tough time getting some kind of Query to work.

This is used in an Employee Look-up Window and i'm trying to make people able to search with certain conditions.

All of the search conditions are fields included in my employee table except 1.

That one is an Employer number so this way, they could if needed look into a specific employer.

Alright here is my problem:

The main query is build using the App Builder and is simply :
Code:
EACH appl.employee WHERE ~{&KEY-PHRASE}
      AND  appl.employee.status-code <= 6 NO-LOCK
    ~{&SORTBY-PHRASE} INDEXED-REPOSITION

This works perfectly, and i can add search criteria's using my &KEY-PHRASE.

BUT! I would like to be able to add a condition such as :
Code:
AND CAN-FIND(first employment WHERE employment.empl-no = employee.empl-no AND
                             employment.employer = SearchCriteria NO-LOCK)

But i discovered that Progress doesn't like CAN-FIND in queries! Anyone knows how to fix that? Here is what i would have liked it to look like:

Code:
EACH appl.nss-employee WHERE ~{&KEY-PHRASE}
      AND  appl.nss-employee.status-code <= 6 NO-LOCK
    ~{&SORTBY-PHRASE} 
      AND CAN-FIND(first employment WHERE employment.empl-no = employee.empl-no AND
                             employment.employer = SearchCriteria NO-LOCK)
     INDEXED-REPOSITION


Any ideas?
 

GregTomkins

Active Member
Are you sure that's the problem? I am too lazy to actually try this, and it's not clear whether you are talking about static or dynamic queries or actually just a WHERE clause.

Anyhow, your syntax looks highly iffy, with the NO-LOCK in between the AND's and the SORT-PHRASE in between like that. Also you don't need NO-LOCK on CAN-FIND, but I doubt that matters. I think maybe you really want to do some kind of a join here.

Ugh, not your fault, but all that preprocessor crap, I forgot how much I hate the CrappBuilder...
 
lol all code is a copy/paste from the Query builder screen from Progress lol... So the iffy syntax is from our friends at Progress :)
 
EACH appl.nss-employee WHERE ~{&KEY-PHRASE}
AND appl.nss-employee.status-code <= 6 NO-LOCK
~{&SORTBY-PHRASE}
AND CAN-FIND(first employment WHERE employment.empl-no = employee.empl-no AND
employment.employer = SearchCriteria NO-LOCK)

=>
EACH appl.nss-employee WHERE ~{&KEY-PHRASE}
AND appl.nss-employee.status-code <= 6 NO-LOCK,
first employment OUTER-JOIN of nss-employee
WHERE employment.empl-no = employee.empl-no AND
employment.employer = SearchCriteria NO-LOCK
 
This is quite close. Not sure at 100%.
Thing is, the last condition will not be used all the time...

So my tought was to use a Pre-Proc.

Here is what i want to do but of course, it doesn't work :p

Code:
IF ENTRY(1,SearchCriteria) = "Employer" THEN DO:
   SCOPED-DEFINE CanFind CAN-FIND(first employment WHERE employment.empl-no = employee.empl-no AND employment.employer = Entry(2,SearchCriteria) NO-LOCK)
END.
ELSE DO:
   SCOPED-DEFINE CanFind TRUE
END.

So the Query would be:

Code:
EACH appl.nss-employee WHERE ~{&KEY-PHRASE}
      AND  appl.nss-employee.status-code <= 6 NO-LOCK
    ~{&SORTBY-PHRASE} 
      AND {&CanFind}
     INDEXED-REPOSITION

This Way, my query will only bring me the Employees of the requested Employer!
 

RealHeavyDude

Well-Known Member
Let me see if get this right:

You want to change the query where dynamically at run time depending on certain criteria? There is no way that you will achieve this with pre-processor directives because they get resolved at compile time.

If you are not at least on Version 9 of Progress discard the rest of my post!

I suppose, since you are using the query builder this query is attached to a browse widget. You can grab the handle to that query ( which is really a static query object which is not all too different from a dynamic query object, the only difference is that you can't set the buffers at run time ). Now comes the cool part: From that moment on you can dynamically set the query where and open the query although it has been defined at design time with the query builder using that handle. For that you can use the QUERY-PREPARE () and QUERY-OPEN () methods.

Maybe that's more like what you have in mind.


HTH, RealHeavyDude.
 
Was able to do it.
It's working but it's pretty slow unless you have some stuff in the KEY-PHRASE for the Employee table.

Here is the Open query i did. not clean but it's working. I really to improve speed tough.:
Code:
IF SearchCriteria EQ "":U THEN DO:
OPEN QUERY {&SELF-NAME} FOR EACH employee NO-LOCK  WHERE ~{&KEY-PHRASE}
      AND  employee.status-code LE 6
    ~{&SORTBY-PHRASE} ,
    FIRST employment OUTER-JOIN WHERE
          (IF SearchCriteria EQ "":U THEN employment.employer = employment.employer ELSE employment.employer EQ SearchCriteria) AND
          employment.empl-no EQ employee.empl-no AND
          employment.Start-date LE gdLoginDate AND
          (employment.End-Date GE gdLoginDate OR employment.End-Date EQ ?)
    INDEXED-REPOSITION.
END.
ELSE DO:
OPEN QUERY {&SELF-NAME} FOR EACH employee NO-LOCK  WHERE ~{&KEY-PHRASE}
      AND  employee.status-code LE 6
    ~{&SORTBY-PHRASE} ,
    FIRST employment WHERE
          (IF SearchCriteria EQ "":U THEN employment.employer = employment.employer ELSE employment.employer EQ SearchCriteria) AND
          employment.empl-no EQ employee.empl-no AND
          employment.Start-date LE gdLoginDate AND
          (employment.End-Date GE gdLoginDate OR employment.End-Date EQ ?)
    INDEXED-REPOSITION.
END.
 
@plus_marca:

The link is not working for me :(
HTTP Status 500 - type Exception report

message: description The server encountered an internal error () that prevented it from fulfilling this request.

exception

org.apache.jasper.JasperException
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:254)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:295)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:241)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:247)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
at com.primus.studioui.P3PFilter.doFilter(Unknown Source)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:213)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:256)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
at org.jboss.web.tomcat.security.JBossSecurityMgrRealm.invoke(JBossSecurityMgrRealm.java:220)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
at org.apache.catalina.valves.CertificatesValve.invoke(CertificatesValve.java:246)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
at org.jboss.web.tomcat.tc4.statistics.ContainerStatsValve.invoke(ContainerStatsValve.java:76)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
at org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2417)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:180)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
at org.apache.catalina.valves.ErrorDispatcherValve.invoke(ErrorDispatcherValve.java:171)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:172)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:65)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:174)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
at org.apache.coyote.tomcat4.CoyoteAdapter.service(CoyoteAdapter.java:197)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:781)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:549)
at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:605)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:677)
at java.lang.Thread.run(Unknown Source)
root cause

java.lang.NullPointerException
at org.apache.jsp.Group_jsp._jspService(Group_jsp.java:63)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:137)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:210)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:295)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:241)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:247)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
at com.primus.studioui.P3PFilter.doFilter(Unknown Source)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:213)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:256)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
at org.jboss.web.tomcat.security.JBossSecurityMgrRealm.invoke(JBossSecurityMgrRealm.java:220)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
at org.apache.catalina.valves.CertificatesValve.invoke(CertificatesValve.java:246)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
at org.jboss.web.tomcat.tc4.statistics.ContainerStatsValve.invoke(ContainerStatsValve.java:76)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
at org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2417)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:180)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
at org.apache.catalina.valves.ErrorDispatcherValve.invoke(ErrorDispatcherValve.java:171)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:172)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:65)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:174)
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
at org.apache.coyote.tomcat4.CoyoteAdapter.service(CoyoteAdapter.java:197)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:781)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:549)
at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:605)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:677)
at java.lang.Thread.run(Unknown Source)
Apache Tomcat/4.1.29
 

RealHeavyDude

Well-Known Member
Using functions in queries, if you are not very, very, very careful, will result in table scans because the compiler can't bracket an index. You should avoid the usage of functions and if conditions in queries as much as possible.

That's one reason why would go for a dynamic query if I were you.

Regards, RealHeavyDude.
 
Then it will not work properly.

The OUTER-JOIN is what's getting me the result. If i put absolutely nothing in my search criteria and load my &KEY-PHRASE with something, it's as fast as lightning.
If i put nothing in my &KEY-PHRASE and something in my SearchCriteria then it's 1min minimum.
 
@RealHeavyDude:
Never used them before so i'm not quite sure how to do it :)
I'll try to find some stuff about the Dynamic Queries.
 

RealHeavyDude

Well-Known Member
Basically what you can do (using thunderbird as editor so it's not syntax checked):

DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.
DEFINE VARIABLE cQueryWhere AS CHARACTER NO-UNDO.
DEFINE VARIABLE cValue AS CHARACTER NO-UNDO.
DEFINE VARIABLE lOkay AS LOGICAL NO-UNDO.

/* Grab the handle to the query */
ASSIGN hQuery = BROWSE yourBrowseName:QUERY:HANDLE.

/* Now we can use the QUERY-PREPARE but close the query first if it's open */
IF hQuery:IS-OPEN THEN hQuery:QUERY-CLOSE ( ).
ASSIGN cQueryWhere = SUBSTITUTE ( 'FOR EACH table NO-LOCK WHERE table.field = "&1"', cValue ).
ASSIGN lOkay = hQuery:QUERY-PREPARE ( cQueryWhere ) NO-ERROR.

/* If we were successful we now open the query */
IF lOkay THEN hQuery:QUERY-OPEN ( ).

/* Now we can check the index usage */
MESSAGE hQuery:INDEX-INFORMATION
VIEW-AS ALERT-BOX INFO BUTTONS OK.
As you can see you can pass the QUERY-PREPARE method a string that you build at run time which should give you all the flexibility you need and avoid awkward things which hurt performance.


HTH, RealHeavyDude.
 
@RealHeavyDude:

Alright! It worked and i gained a few seconds in my search time but it still is slow...

Ideally, i would need to swap around both table in my for each in order for it to work as fast as lightning Because if my employer # is entered, therefore i need all the employee's with an employment! (You can have employee's without employment and can have employees with multiple employments).

Seems it's not letting me do it :( Any idea? I tried re-setting the buffers with the SET-BUFFERS attribute but it's giving me errors and is not compiling because it says it's linked to a static query.

Code:
/**** Here is my Open Query:


OPEN QUERY {&SELF-NAME} FOR EACH nss-employee NO-LOCK  WHERE ~{&KEY-PHRASE}
         AND  nss-employee.status-code <= 6
         ~{&SORTBY-PHRASE} ,
      FIRST nss-employment WHERE
               nss-employment.SSR = nss-employment.SSR AND
               nss-employment.SSN EQ nss-employee.SSN AND
               nss-employment.Start-date LE gdLoginDate AND
              (nss-employment.End-Date GE gdLoginDate OR nss-employment.End-Date EQ ?)
      INDEXED-REPOSITION.

/***** Here is my setup code ******/
ASSIGN hQuery = BROWSE br_table:QUERY:HANDLE
   cQueryWhere = SUBSTITUTE ( 'FOR EACH nss-employee NO-LOCK WHERE nss-employee.status-code <= 6, FIRST nss-employment WHERE nss-employment.SSR EQ "&1" AND nss-employment.SSN EQ nss-employee.SSN AND nss-employment.Start-date LE &2 AND (nss-employment.End-Date GE &2 OR nss-employment.End-Date EQ ?) INDEXED-REPOSITION', cValue[9], gdLoginDate)
              lOkay = hQuery:QUERY-PREPARE ( cQueryWhere ) NO-ERROR.

MESSAGE lOkay SKIP
               cQueryWhere
              VIEW-AS ALERT-BOX INFO BUTTONS OK.
IF lOkay THEN hQuery:QUERY-OPEN ( ).
 

RealHeavyDude

Well-Known Member
The reason why SET-BUFFERS () is not working because it's a static query object where static means it's defined at compile time. Only dynamic query objects which you create at run time with CREATE QUERY will let you do that. That's the limitation of static query objects.

But, you could use a dynamic query object. At run time you could set the QUERY attribute of the browse widget to the handle of a dynamic query.

Something like (again I used thunderbird as editor, so it's not syntax checked):

DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.
DEFINE VARIABLE cQueryWhere AS CHARACTER NO-UNDO.
DEFINE VARIABLE cValue AS CHARACTER NO-UNDO.
DEFINE VARIABLE lOkay AS LOGICAL NO-UNDO.

/* Create the query object */
CREATE QUERY hQuery.

/* Set the buffers */
hQuery:SET-BUFFERS ( BUFFER myTable1:HANDLE, BUFFER myTable2:HANDLE ).

/* Do the query prepare stuff ... */

/* Unlink the browse widget from the static query and link it with the dynamic one */
ASSIGN BROWSE yourBrowserName:QUERY = ?.
ASSIGN BROWSE yourBrowserName:QUERY = hQuery.

/* Open query stuff ... */


/* VERY IMPORTANT: To avoid memory leaks - if you create an object you must make sure it's deleted */
IF VALID-HANDLE ( hQuery ) THEN DO:
DELETE OBJECT hQuery.
ASSIGN hQuery = ?.
END.
Could do.

HTH, RealHeavyDude.
 
So close! Yet no cigars...
I'm wandering if it's not coming from all the different Pre-Proc that Progress is using.
I'm getting all the messages before getting a weird error mess...


Code:
          CREATE QUERY hQuery. 
           hQuery:SET-BUFFERS(BUFFER nss-employment:Handle, BUFFER nss-employee:HANDLE).
           ASSIGN /* hQuery = BROWSE br_table:QUERY:HANDLE */
                  /* cQueryWhere = SUBSTITUTE ( 'FOR EACH nss-employee NO-LOCK WHERE nss-employee.status-code <= 6, FIRST nss-employment WHERE nss-employment.SSR EQ "&1" AND nss-employment.SSN EQ nss-employee.SSN AND nss-employment.Start-date LE &2 AND (nss-employment.End-Date GE &2 OR nss-employment.End-Date EQ ?) INDEXED-REPOSITION', cValue[9], gdLoginDate). */
                  cQueryWhere = SUBSTITUTE ( 'FOR EACH nss-employment NO-LOCK WHERE nss-employment.SSR EQ "&1" AND nss-employment.SSN EQ nss-employee.SSN AND nss-employment.Start-date LE &2 AND (nss-employment.End-Date GE &2 OR nss-employment.End-Date EQ ?), FIRST nss-employee NO-LOCK WHERE nss-employee.status-code <= 6 AND nss-employee.SSN EQ nss-employment.SSN USE-INDEX nss-employee INDEXED-REPOSITION', cValue[9], gdLoginDate). 
           
           ASSIGN lOkay = hQuery:QUERY-PREPARE ( cQueryWhere ) NO-ERROR.
           /* If we were successful we now open the query */
           
           MESSAGE lOkay SKIP
                   cQueryWhere
               VIEW-AS ALERT-BOX INFO BUTTONS OK.
           IF lOKAY THEN DO:
              ASSIGN BROWSE br_table:QUERY = ?.
              ASSIGN BROWSE br_table:QUERY = hQuery.
           END. 
           MESSAGE "Objects Assigned"
               VIEW-AS ALERT-BOX INFO BUTTONS OK.
           IF lOkay THEN hQuery:QUERY-OPEN ( ).
           MESSAGE "Query Open"
               VIEW-AS ALERT-BOX INFO BUTTONS OK.


It also messes up my display. All my columns are gone.
 

RealHeavyDude

Well-Known Member
Would you please post the error messages you get. Maybe I've forgotten something in my sample code. Maybe you loose the columns in the browse because of that.

Right now I have no access to a Progress development environment ...

Regards, RealHeavyDude.
 
After fidling arround a bit, i was able to produce absolutly no error messages...
But all my columns diseaper. :( So nothing is displayed... Do i need to re-defined everything for the display? It still can use the same fields as they are available...


Code:
           CREATE QUERY hQuery. 
           hQuery:SET-BUFFERS(BUFFER nss-employment:Handle, BUFFER nss-employee:HANDLE).  
           ASSIGN cQueryWhere = SUBSTITUTE ( ' FOR EACH nss-employment NO-LOCK WHERE nss-employment.SSR EQ "&1" AND nss-employment.Start-date LE &2 AND (nss-employment.End-Date GE &2 OR nss-employment.End-Date EQ ?), FIRST nss-employee NO-LOCK WHERE nss-employee.SSN EQ nss-employment.SSN AND nss-employee.status-code LE 6 INDEXED-REPOSITION', cValue[9], gdLoginDate).   
           
           ASSIGN lOkay = hQuery:QUERY-PREPARE ( cQueryWhere ) NO-ERROR.
           /* If we were successful we now open the query */
           
           MESSAGE lOkay SKIP
                   cQueryWhere
               VIEW-AS ALERT-BOX INFO BUTTONS OK.
           IF lOKAY THEN DO:
              ASSIGN BROWSE br_table:QUERY = hQuery. 
              hQuery:QUERY-OPEN ( ).
           END.
 
My Error message was cased by a function setting a color on a column but since all columns are not displayed, it was not happy lol

Still, Can't get anything to display on the screen...
It blanks all my columns.
 
Top