MySQL for Python
上QQ阅读APP看书,第一时间看更新

Changing queries dynamically

But what if the user does not want to submit a precise query but needs a list of the possibilities? There are a couple of ways to clarify the search. We could first keep a list of the common search queries. This is something done often by the likes of Google and Yahoo!. This works very well with large datasets served through web servers because it uses a static list of terms and simply culls them out. For more dedicated applications, one can use MySQL's pattern matching ability to present known options on-the-fly.

Pattern matching in MySQL queries

Where Python's regular expression engine is very robust, MySQL supports the two following metacharacters for forming regular expressions:

  • %: Zero or more characters matched in aggregate
  • _: Any single character matched individually

Pattern matching is always a matter of comparison. Therefore, with either of these, never use operators of equality.

SELECT * FROM menu WHERE name = 's%';                   WRONG
SELECT * FROM menu WHERE name <> 's%';            WRONG

Instead, use the keywords LIKE and NOT LIKE.

SELECT * FROM menu WHERE name LIKE 's%';                RIGHT
SELECT * FROM menu WHERE name NOT LIKE 's%';    RIGHT

Using metacharacters, one can match records using very irregular terms. Some of the possible combinations follow below:

  • s%: A value that begins with the letter s
  • %s: A value that ends with the letter s
  • %s%: A value that contains the letter s
  • s%l: A value that begins with s and ends with l
  • s%l%: A value that begins with s and contains at least one instance of the letter l
  • s_l%: A value that begins with s and whose third letter is l
  • _____: A five letter value (that is five underscore characters in succession)
  • __%: A value with at least two characters

Putting it into practice

For a smaller dataset or even larger datasets served over low-contest or no-contest connections (for example local servers or dedicated LAN connections), there is the option of running a live query to present the user with the possible options. If the user has specified the database and table to be used, as in the example seen previously, then it is a small matter to match patterns in a column using LIKE and a regular expression.

The MySQL sentence for what we are doing, along with its results, is as follows:

mysql> SELECT name FROM menu WHERE name LIKE 's%';
+--------+
| name |
+--------+
| salmon | 
| sole | 
+--------+
2 rows in set (0.00 sec)

Tip

It is important to phrase the query in such a way as to narrow the returned values as much as possible.

Here, instead of returning whole records, we tell MySQL to return only the namecolumn. This natural reduction in the data reduces processing time for both MySQL and Python. This saving is then passed on to your server in the form of more sessions able to be run at one time.

In Python, the preceding statement would look like this:

column = 'name'
term = 's%'
statement = """select %s from menu where name like '%s'""" %(column, term)

Using the conversion specifier (%s), this code can easily be adapted for more dynamic uses.

Having restricted the parameters of the search, we are in greater control of the results and can therefore anticipate the number of fields in each record returned. We then have to execute the query and tell the cursor to fetch all of the records. To process the records, we iterate over them using a pattern similar to what we used previously:

command = cur.execute(statement)
results = cur.fetchall()

column_list = []
for record in results:
    column_list.append(record[0])

print "Did you mean:"
for i in xrange(0, len(column_list)):
    print "%s.  %s" %(i+1, column_list[i])
option = raw_input ('Number:')
intoption = int(option)

The results for this code are:

Did you mean:
1. salmon
2. sole
Number:

Naturally, we must then test the user input. After that, we can process the query and return the results.

This example is shown using terminal options so we do not use any JavaScript to transfer the options. However, in modern day reality, any application that relies on a web browser—either for background processing or for a primary interface, can use this code with minor modifications.