I.T. Discussion Community!
-Collapse +Expand
Paradox
Search Paradox Group:

Advanced
-Collapse +Expand Paradox To/From
To/FromCODEGuides
-Collapse +Expand Paradox Store
PRESTWOODSTORE

Prestwood eMagazine

April Edition
Subscribe now! It's Free!
Enter your email:

   ► KBDesktop Data...Paradox & Ob...P9 Book: Pow...   Print This     
  From the May 2013 Issue of Prestwood eMag
 
Paradox P9 Book: Power Programming:
Power: Chapter 11, Programming with Queries
 
Posted 16 years ago on 3/20/2003 and updated 10/19/2010
Take Away: Chapter 11, "Programming with Queries" from Paradox 9 Power Programming by Mike Prestwood.

KB100202



The technique of asking questions about data by providing an example of the answer you expect is called query by example (QBE). You can use this tool to ask questions about your data and analyze it. A query is a means of extracting sets of information from a database or table. You can base forms and reports on a subset of your data by using a query as the first table in your data model. You can even use a live query as this first table. And you can also create queries on the fly in ObjectPAL. The Query variable is a handle to a QBE query.

Queries

Queries are a very important part of any database. Having a large amount of data isn’t useful unless you can analyze it. Queries are what you use to analyze your data. Sometimes they are the only way to get certain information about a product. Paradox delivers a graphical QBE that makes it easier than ever to create queries and get fast answers. You can access up to 24 tables in a single query. Join, outer join, inclusion, and set operations are available for full relational queries.

QBE has two functions—namely, as an end-user tool and as a way to use a subset of all the data. You can use QBE to develop specialized forms and reports. Important query methods and procedures include the following:

  • executeQBE() Executes a QBE query.
  • QUERY Begins a QBE statement or string.
  • readFromFile() Reads a QBE file into a query variable.
  • readFromString() Reads a string into a query variable.
  • writeQBE() Writes a query statement to a specified file.

Displaying the Query Window

Suppose that you want to bring up the query window with a particular query. To do this, you can use sendKeys() from the system type. For example, change your working directory to Paradox’s Samples directory and type line 3 into the pushButton event of a button.

1: ;Button :: pushButton
2: method pushButton(var eventInfo Event)
3: sendKeys("%foqworld{ENTER}") ;Emulates pressing keys.
4: endMethod

sendKeys() emulates the user pressing keys. The first part of the preceding code emulates the user pressing alt-f-o-q, which is the same as selecting File | Open | Query. The second half, WORLD{ENTER}, specifies the name of the query to open and presses the return key.

Executing a Saved Query

The term "query" in ObjectPAL refers to the Query variable. The Query variable is your handle to a query. Just as you can declare a Form variable and open it, you can declare a Query variable, read a file into it, and execute it. For example, change your working directory to Paradox’s Samples directory and type lines 2–7 into the pushButton event of a button.

1: method pushButton(var eventInfo Event)
2: var
3: q Query ;Declare a Query variable.
4: endVar
5:
6: q.readFromFile("CUSTOMERLIST.QBE") ;Read in QBE.
7: q.executeQBE() ;Execute QBE.
8: ;Open up the answer table in your private directory.
9: endMethod

Running a Query from a Button

Suppose that you have an existing query, CUSTOMERLIST.QBE, that you want to run, then show the results in a table window and enable Paradox to delete the answer table automatically when it exits.

    1. Change your working directory to Paradox’s Samples directory and create a query based on the CUSTOMER.DB table and check the Customer Name and Phone fields, as shown here. Save the query as CustomerList.qbe.
    2. Illustration 1

    3. Create a new form. Add a button labeled Run Query File to it, as shown here:
    4. Illustration 2

    5. Add lines 3–10 to the pushButton event of the Run Query File button to execute the query. Line 4 declares a Query variable, and line 5 declares a TableView variable. Line 8 uses readFromFile() to read the QBE file CUSTOMERLIST.QBE into the q Query variable. Then, executeQBE() is used in line 9 to run the query and create a table named __ANS.DB in your private directory.
    6. 1: ;Button :: pushButton
      2: method pushButton(var eventInfo Event)
      3: var
      4: q Query ;Declare query variable.
      5: tv TableView
      6: endVar
      7:
      8: q.readFromFile("CustomerList.QBE") ;Read in QBE.
      9: q.executeQBE(":priv:__ans") ;Optional: specify answer table.
      10: tv.open(":priv:__ans")
      11: endMethod

    7. Check the syntax, save the form as Query.fsl, run the form, and click the button. The query runs and creates a table named __ANS.DB in your private directory. Then the table is opened (see Figure 11-1). When you exit Paradox, the table is deleted.

Figure 1: QUERY.FSL demonstrates how to run a query from ObjectPAL

This last step of using two underscores at the beginning of a file in your private directory is important. It is also interesting, because it takes advantage of an undocumented feature of Paradox. Any file in the private directory that starts with two underscores is deleted when the program is exited. This is a normal part of the cleanup process of Paradox. In addition, the files are not listed in the browser or Project Viewer.

Using a Query Statement with executeQBE()

In addition to executing a query file—for example, CUSTOMERLIST.QBE—you can code a query inside your code with ObjectPAL. First, you declare a Query variable.

1: var
2: q Query
3: endVar

Next, you use the defined Query variable to start the query section in your code. Then comes the actual Query string. For example:

1: q = Query
2: WORLD.DB | COUNTRY | CURRENCY |
3: | Check | Check ..Dollar.. |
4: EndQuery

Typing all these field names, checks, and values would be a hassle, to say the least. In essence, you have to learn a whole new programming language, the QBE language. Luckily, ObjectPAL provides an easier way. A saved QBE file is simply a text file. Therefore, you can use the Edit | Paste From option to paste the text file and alter it as needed. Then, use executeQBE() the way you did in the previous example. For example:

1: q.executeQBE(":PRIV:ANSWER.DB")

Using executeQBE

Suppose that you want to execute a query by using the ObjectPAL Query variable.

Step By Step

    1. Change your working directory to the Paradox’s Samples directory and create a new query based on CUSTOMER.DB. Check the Name and Phone fields and query for all the records with Negril in the City field, as shown here. Save the query as CustomerQuery.QBE.
    2. Illustration 3

    3. Create a new form and add a button labeled Query Customer to it.
    4. The easiest way to a build a query in ObjectPAL is to build it interactively and paste it into the Editor. A QBE file is simply a text file, as you can see in the illustration shown here. It can be pasted directly into the Editor. The easiest way to do this is to use the Edit | Paste From option of the editor.
    5. Illustration 4

    6. Paste the text from CustomerQuery.qbe into the pushButton event of the Query Customer.DB button and alter as follows. This illustration shows how the code looks after you insert the QBE file:
    7. Illustration 5

      Lines 4 and 5 declare the Query and TableView variables. Lines 8–14 contain the query that is pasted in. Only line 8 has been altered. Line 9 specifies where the answer table should be created. If you leave out line 9, the default is :PRIV:ANSWER.DB. In this case, if you delete line 9, you will get the same result. Line 16 uses executeQBE() to execute the Query variable, and line 17 displays the table that results.

      1: ;Button :: pushButton
      2: method pushButton(var eventInfo Event)
      3: var
      4: q Query
      5: tv TableView
      6: endVar
      7:
      8: q = Query
      9: ANSWER: :PRIV:ANSWER.DB
      10:
      11: customer.db | Name | City | Phone |
      12: | Check | ..Negril.. | Check |
      13:
      14: EndQuery
      15:
      16: executeQBE(q)
      17: tv.open(":PRIV:ANSWER.DB")
      18: endMethod

    8. Check the syntax, save the form as QUERY1.FSL, and run it. Click the button. The query is run, and the table is shown in a table window, as seen here:

Illustration 6

Passing a Value to a Query

You know how to execute a QBE file on disk and how to execute values stored in your code. The next step is to learn how to pass a value to a query. Often, you’ll want to enable the user to enter values and to query the table for the values entered. In effect, you simulate the query editor. Use a tilde variable whenever you want to pass a value to a query.

Using a Tilde (~) Variable

Suppose that you want to pass a value to a query and have the query search for that value. The next example demonstrates how to use a tilde variable to set values for a query, run the query, and display the result.

Step By Step

    1. Change your working directory to Paradox’s Samples directory. Create a new form. Place an unbound field named Enter_City and labeled Enter Search String. Also, place a button labeled Query Customer Table on the form, as shown here:
    2. Illustration 7

    3. Before entering the code in step 3, open the CustomerQuery.qbe query you created in the previous example. Then, paste the query directly into your code and alter it by replacing the Negril value with the tilde and variable name (see the next step).
    4. The altered pushButton event should look like the following code listing. Lines 4–6 declare the variables. Line 9 passes the value in the Enter Search String field to the s variable. Lines 11–18 are the query that you pasted. Lines 11 and 16 have been altered from the value that was pasted in. Line 20 executes the Query variable, and line 21 displays the result.
    5. 1: ;Button :: pushButton
      2: method pushButton(var eventInfo Event)
      3: var
      4: sName String
      5: qryCustomer Query
      6: tvAnswer TableView
      7: endVar
      8:
      9: sName = Enter_City.value
      10:
      11: qryCustomer = Query
      12:
      13: ANSWER: :PRIV:ANSWER.DB
      14:
      15: customer.db | Name | City | Phone |
      16: | Check | ..~sName.. | Check |
      17:
      18: EndQuery
      19:
      20: executeQBE(qryCustomer)
      21: tvAnswer.open(":priv:answer.db")
      22: endMethod

    6. Check the syntax, save the form as QUERY2.FSL, and run it. Type a value, and click the button. The value appears. If you don’t type a value into the field, all records are displayed.

Illustration 8

Rather than bring the query editor up for the user to use (as demonstrated previously), you can simulate the query editor on a form with an interface that is more specific than File | Open | Query.

Executing a Query Stored in a String

If you want, you can build a query in a string variable and then use readFromString() to read the string into a Query variable. After the query string is in a Query variable, use executeQBE() to execute it. Because you have tilde (~) variables, this technique is not really needed, but it can be useful. The following code executes the same CustomerQuery.qbe query you used in a previous example in this chapter.

1: ;Button :: pushButton
2: method pushButton(var eventInfo Event)
3: var
4: sQuery String
5: s1 String
6: s2 String
7: s3 String
8: s4 String
9: s5 String
10: qryCustomer Query
11: tvAnswer TableView
12: endVar
13:
14: errorTrapOnWarnings(Yes)
15:
16: s1 = "Query\n"
17: s2 = "ANSWER: :PRIV:ANSWER.DB\n"
18: s3 = "customer.db | Name | City | Phone |\n"
19: s4 = " | Check | ..San Jose.. | Check |\n"
20: s5 = "EndQuery"
21:
22: sQuery = s1 + s2 + s3 + s4 + s5
23:
24: qryCustomer.readFromString(sQuery)
25: qryCustomer.executeQBE()
26: if not tvAnswer.open(":PRIV:ANSWER") then errorShow() endIf
27: endMethod

Tip: Here is a tip if you are having problems with a query and you are not sure whether the problem is the query string itself or something else. Use writeQBE() to write the Query variable out to a file, and then try to run the query interactively. In addition, you can use isQueryValid(), which tells you if the query is valid. The benefit of using writeQBE() is that you can open the query and look at it.

Another debugging technique is to use the errorShow() procedure, as in the following example:

1: if not qryCustomer.executeQBE() then errorShow() endIf

Points to remember about using readFromString() are as follows:

  • End each line of the query with \n, which represents a line feed.
  • A quoted string is limited to 255 characters.
  • Use multiple quoted strings for quoted strings longer than 255.
  • Use the errorShow() procedure to check whether the query executes.

Using an In-Memory TCursor

In-memory TCursors are interesting because they are fast and they are not connected to the live data. You can ask "what if" questions of the data before writing the data to the live database. The command wantInMemoryTCursor() is used when you want to specify how a TCursor is created resulting from a query. Following is the syntax:

wantInMemoryTCursor(const yesNo Logical)

Note: The procedure wantInMemoryTCursor(Yes) is only necessary for queries that would normally produce live query views. If the query doesn’t meet the conditions for a live query, and the answer is a TCursor, the TCursor will be in memory nonetheless.

Specify Yes (or Null) to build the TCursor in-memory; the TCursor is not connected to a table. Specify No to attach the TCursor to the live data. If you do not call wantInMemoryTCursor() before you execute a query to a TCursor, the default is the same as if you called it and passed it No; the resulting TCursor is live to the data. The exception is with multitable queries that specify an answer TCursor, which will always produce an in-memory TCursor. Here is how you use wantInMemoryTCursor() with a query to gain access to an in-memory TCursor:

1: ;Button :: pushButton
2: method pushButton(var eventInfo Event)
3: var
4: qryCustomerQuery Query
5: tcCustomerQuery TCursor
6: endVar
7:
8: qryCustomerQuery.wantInMemoryTCursor(Yes)
9: qryCustomerQuery.readFromFile("CustomerQuery.QBE")
10: qryCustomerQuery.executeQBE(tcCustomerQuery)
11:
12: ;Utilize in-memmoy TCursor here.
13: endMethod

This command also works with SQL variables. In fact, SQL variables are very similar in nature to Query variables. You manipulate them with ObjectPAL using the same techniques. Other methods that are useful with in-memory TCursors include isInMemoryTCursor(), isView(), and instantiateView(). isInMemoryTCursor() returns True when the TCursor is an in-memory TCursor. isView() returns True if the TCursor is connected to live data. Finally, instantiateView() copies an in-memory TCursor to a physical table.

Query Methods

There are query methods to generate and modify queries using ObjectPAL. These methods include appendTable(), setCriteria(), setQuerySortOrder(), setCheck(), and setRowOp(). These methods are not as easy as they may seem. Here are a few pointers:

  • You can set a row operator to check all the fields, but if you want to check all fields but one, you cannot use checkRow() and you need to setCheck() each field.
  • To set the Answer table sort order, you must fill an array with every checked field; if you remove or add a field to the answer table of the query, you must fix the array and reuse setAnswerSortOrder().
  • setAnswerFieldOrder() interferes with Delete, Insert and Changeto queries. It also will inhibit removeTable().

This next example uses appendTable() to add a table to a query image, checkRow() to check all the rows of the query image, executeQBE() to run the query, and ,finally, open() to open the answer table. Change your working directory to the Samples directory and type lines 3–14 into the pushButton event of a button. Figure 11-2 shows the final result.

1: ;Button :: pushButton
2: method pushButton(var eventInfo Event)
3: const
4: sAns = ":priv:__ans.db" ;Path to answer table.
5: endConst
6: var
7: qCustomers Query
8: tvCustomers TableView
9: endVar
10:
11: qCustomers.appendTable("CUSTOMER.DB") ;Add table to query.
12: qCustomers.checkRow("CUSTOMER.DB", CheckCheck) ;Check all fields.
13: qCustomers.executeQBE(sAns) ;Execute query.
14: tvCustomers.open(sAns) ;Display table.
15: endMethod

Figure 2: Example using appendTable()

Summary

In this chapter, you learned that a query is what you use to ask a table a question. You learned how to use sendKeys() to open up a query image for your users. You learned how to generate and use queries in ObjectPAL. You learned how to execute a saved query, and execute a query string with executeQBE(). You learned how to pass a value to a query using a tilde variable. Finally, you learned how to work with live queries, in-memory TCursors, and some of the Paradox query methods.


Comments

1 Comments.
Share a thought or comment...
Comment 1 of 3

Thanks.

---
jlockley
Posted 9 years ago

Comment 2 of 3

Thank you !

---
Peter Dissing
Posted 39 months ago

Comment 3 of 3

You're welcome Peter!

Posted 39 months ago
 
Write a Comment...
...
Sign in...

If you are a member, Sign In. Or, you can Create a Free account now.


Anonymous Post (text-only, no HTML):

Enter your name and security key.

Your Name:
Security key = P1244A1
Enter key:
KB Post Contributed By Mike Prestwood:

Mike Prestwood is a drummer, an author, and creator of the PrestwoodBoards online community. He is the President & CEO of Prestwood IT Solutions. Prestwood IT provides Coding, Website, and Computer Tech services. Mike has authored 6 computer books and over 1,200 articles. As a drummer, he maintains play-drums.com and has authored 3 drum books. If you have a project you wish to discuss with Mike, you can send him a private message through his PrestwoodBoards home page or call him 9AM to 4PM PST at 916-726-5675 x205.

Visit Profile

 KB Article #100202 Counter
51836
Since 4/2/2008
Follow PrestwoodBoards on: 


©1995-2019 PrestwoodBoards  [Security & Privacy]
Professional IT Services: Coding | Websites | Computer Tech