Dynamic Queries in Progress ABL/4GL Based On Inputs

Often I run into queries where the “where” clause is put together by what has been entered by the user. These tend to be a complete mess in code by programmers not sure how to put this together.

One basically needs a flag to know what is being connected together and what is not.

Here is a “design pattern” of sorts one can use for these kinds of queries.

  • Make up your basic query phrase, in this case “for each cust” where cust is the table name.

 QueryPhrase = "for each cust".

  • Basically take in the values that could be present, in this case CustomerNumber and CustomerName.

 CustomerNumber = get-value("ByCustomerNumber").

 CustomerName = get-value("ByCustomerName").

  • If any of the “where” clause information is present, append “ where “ to the query phrase. You know there is going to be a delimiter on the query by the mere existence of the values.

 if CustomerNumber <> "" or CustomerName <> "" then QueryPhrase = QueryPhrase + " where ".

  • Next build your where clause. If the data is present, then append the where clause on to the query phrase and include that an and is need by setting a logical flag to yes. We use a logical flag because we don’t know yet if any of the other data is present, but we want to “remember” an “and” is needed when other data shows it’s self is there.

In the code below, I begin using the design on the construction of the QueryPhrase:

 if CustomerNumber <> "" then do:

   QueryPhrase = QueryPhrase + (if AndNeeded then " and " else "")

                 + ”cust.cust_num begins '" + CustomerNumber + "'".

   AndNeeded = true.

 end. // if CustomerNumber <> ""

That construct can be used for whatever fields are being used to restrict the data being returned.

Here it is in actual usable code (using Webspeed on the WDS application):

procedure DoLookup:

 define variable HdlTheQuery as widget-handle no-undo.

 define variable QueryPhrase as character no-undo.

 define variable CustomerNumber as character no-undo.

 define variable CustomerName as character no-undo.

 define variable FieldName as character no-undo.

 define variable AndNeeded as logical init false no-undo.


 define variable Counter as integer no-undo.

 define variable MaxCounter as integer init 100 no-undo.

 define variable H as lib.HTMLTools no-undo.

 H = new lib.HTMLTools().

 QueryPhrase = "for each cust".

 CustomerNumber = get-value("ByCustomerNumber").

 CustomerName = get-value("ByCustomerName").

 FieldName = get-value("FieldName").

 // Determine if we are going to have any where clauses

 if CustomerNumber <> "" or CustomerName <> "" then QueryPhrase = QueryPhrase + " where ".

 // Try clause one

 if CustomerNumber <> "" then do:

   QueryPhrase = QueryPhrase + (if AndNeeded then " and " else "")

                 + ”cust.cust_num begins '" + CustomerNumber + "'".

   AndNeeded = true.

 end. // if CustomerNumber <> ""

 // Try clause two

 if CustomerName <> "" then do:

   QueryPhrase = QueryPhrase + (if AndNeeded then " and " else "")

                 + "index(cust.name, '" + CustomerName + "') > 0".

   AndNeeded = true.

 end. // if CustomerName <> ""

 create query HdlTheQuery.

 HdlTheQuery:set-buffers (buffer cust:handle).

 HdlTheQuery:query-prepare (QueryPhrase).

 HdlTheQuery:query-open ().

 -->

 <table>

   <tr>

     <td>Customer Number</td><td>Customer Name</td>

   </tr> 

 <!--WSS

 repeat:

   HdlTheQuery:get-next().

   if HdlTheQuery:query-off-end then leave.


   Counter = Counter + 1.

   if Counter = MaxCounter then leave.

   -->

   <tr>

     <td>`H:AnswerHyperLink(FieldName, cust.cust_num, cust.cust_num)`</td>

     <td>`substitute("&1 &2", cust.name, cust.name2)`</td>

   </tr>

   <!--WSS

 end. // repeat

 -->

 </table>

 <!--WSS

 HdlTheQuery:query-close ().

 delete object HdlTheQuery.

end.


This is just a quick hint for those who may need to build query clauses on the fly.


Many thanks for posting this, Scott! Progress provides instructions for all the components in their online documentation, but your working sample was exactly what I needed to build my first dynamic query in 4GL or anywhere else!

Like
Reply

Have you considered any security and value validation when building this approach? You could be leaving yourself open to sql injection.

Like
Reply

I miss things like this from the PEG.

To view or add a comment, sign in

More articles by Scott Augé

  • Useful Tool: PHP Wiki (mediawiki)

    So many times programmers (or other) want a tool that can be a quick document for work out there. Something to answer…

    1 Comment
  • Management Article: What is quality software?

    (This is from a E-Zine for developing in Progress. URLs and such are out dated.

  • Menus And The Like On PHP Programs

    Since it is snowy out today and I have experienced four stokes so don't mind the spelling if it you see an error, I…

  • GetValue() for form/url nvp and cookies with PHP

    When dealing with PHP and you have Webspeed experience (http://progress.com), it might be useful to create a GetValue()…

  • PHP to 4GL/ABL

    Added Entry() and NumEntries() to PHP code for a string of comma delimited substrings like the ABL/4GL has. Also…

  • PHP Code and Dictionary Help Tools

    There are a lot of times when a form on a web app wants information already in the database. Such as the example below:…

  • Queue in PHP (Code)

    Of course if I write about Stacks(1) (LIFO - Last In, First Out), then I got to write about Queues(1) (FIFO - First In,…

  • Simple stack in PHP (Code)

    Here is a class called Stack that implements a stack. A stack is one of the basic data structures one learns in college.

  • Simple stack in PHP/Maria (Dictionary)

    This is a dictionary used for a simple stack code in an upcoming article. First of all, what is a stack? Well, it is…

  • HTML/JAVASCRIPT Validating Inputs (using Workbench)

    Had a question: How do you validate inputs? (I do pay attention to my comments!) A good question (and gives me the…

Others also viewed

Explore content categories