Handling NULL Values in Result Sets

2.9.1 Problem

A query result includes NULL values, but you're not sure how to tell where they are.

2.9.2 Solution

Your API probably has some value that represents NULL by convention. You just have to know what it is and how to test for it.

2.9.3 Discussion

Recipe 2.9 described how to refer to NULL values when you send queries to the database. In this section, we'll deal instead with the question of how to recognize and process NULL values that are returned from the database. In general, this is a matter of knowing what special value the API maps NULL values onto, or what function to call. These values are shown in the following table:

Language

NULL-detection value or function

Perl

undef

PHP

an unset value

Python

None

Java

wasNull( )

The following sections show a very simple application of NULL value detection. The examples retrieve a result set and print all values in it, mapping NULL values onto the printable string "NULL".

To make sure the profile table has a row that contains some NULL values, use mysql to issue the following INSERT statement, then issue the SELECT query to verify that the resulting row has the expected values:

mysql> INSERT INTO profile (name) VALUES('Juan');
mysql> SELECT * FROM profile WHERE name = 'Juan';
+----+------+-------+-------+-------+------+
| id | name | birth | color | foods | cats |
+----+------+-------+-------+-------+------+
| 11 | Juan | NULL | NULL | NULL | NULL |
+----+------+-------+-------+-------+------+

The id column might contain a different number, but the other columns should appear as shown.

2.9.4 Perl

In Perl DBI scripts, NULL is represented by undef. It's easy to detect such values using the defined( ) function, and it's particularly important to do so if you use the -w option on the #! line that begins your script. Otherwise, accessing undef values causes Perl to issue the following complaint:

Use of uninitialized value

To avoid this warning, test column values that might be undef with defined( ) before using them. The following code selects a few columns from the profile column and prints "NULL" for any undefined values in each row. This makes NULL values explicit in the output without activating any warning messages:

my $sth = $dbh->prepare ("SELECT name, birth, foods FROM profile");
$sth->execute ( );
while (my $ref = $sth->fetchrow_hashref ( ))
{
 printf "name: %s, birth: %s, foods: %s
",
 defined ($ref->{name}) ? $ref->{name} : "NULL",
 defined ($ref->{birth}) ? $ref->{birth} : "NULL",
 defined ($ref->{foods}) ? $ref->{foods} : "NULL";
}

Unfortunately, all that testing of column values is ponderous, and becomes worse the more columns there are. To avoid this, you can test and set undefined values in a loop prior to printing them. Then the amount of code to perform the tests is constant, not proportional to the number of columns to be tested. The loop also makes no reference to specific column names, so it can be copied and pasted to other programs more easily, or used as the basis for a utility routine:

my $sth = $dbh->prepare ("SELECT name, birth, foods FROM profile");
$sth->execute ( );
while (my $ref = $sth->fetchrow_hashref ( ))
{
 foreach my $key (keys (%{$ref}))
 {
 $ref->{$key} = "NULL" unless defined ($ref->{$key});
 }
 printf "name: %s, birth: %s, foods: %s
",
 $ref->{name}, $ref->{birth}, $ref->{foods};
}

If you fetch rows into an array rather than into a hash, you can use map( ) to convert any undef values:

my $sth = $dbh->prepare ("SELECT name, birth, foods FROM profile");
$sth->execute ( );
while (my @val = $sth->fetchrow_array ( ))
{
 @val = map { defined ($_) ? $_ : "NULL" } @val;
 printf "name: %s, birth: %s, foods: %s
",
 $val[0], $val[1], $val[2];
}

2.9.5 PHP

PHP represents NULL values in result sets as unset values, so you can use the isset( ) function to detect NULL values in query results. The following code shows how to do this:

$result_id = mysql_query ("SELECT name, birth, foods FROM profile", $conn_id);
if (!$result_id)
 die ("Oops, the query failed
");
while ($row = mysql_fetch_row ($result_id))
{
 while (list ($key, $value) = each ($row))
 {
 if (!isset ($row[$key])) # test for unset value
 $row[$key] = "NULL";
 }
 print ("name: $row[0], birth: $row[1], foods: $row[2]
");
}
mysql_free_result ($result_id);

PHP 4 has a special value NULL that is like an unset value. If you can assume your scripts will run under PHP 4, you can test for NULL values like this:

if ($row[$key] === NULL) # test for PHP NULL value
 $row[$key] = "NULL";

Note the use of the === "triple-equal" operator, which in PHP 4 means "exactly equal to." The usual == "equal to" comparison operator is not suitable here; with ==, the PHP NULL value, the empty string, and 0 all compare equal to each other.

2.9.6 Python

Python DB-API programs represent NULL values in result sets using None. The following example shows how to detect NULL values:

try:
 cursor = conn.cursor ( )
 cursor.execute ("SELECT name, birth, foods FROM profile")
 for row in cursor.fetchall ( ):
 row = list (row) # convert non-mutable tuple to mutable list
 for i in range (0, len (row)):
 if row[i] == None: # is the column value NULL?
 row[i] = "NULL"
 print "name: %s, birth: %s, foods: %s" % (row[0], row[1], row[2])
 cursor.close ( )
except:
 print "Oops, the query failed"

The inner loop checks for NULL column values by looking for None and converts them to the string "NULL". Note how the example converts row to a mutable object prior to the loop; that is done because fetchall( ) returns rows as sequence values, which are non-mutable (read-only).

2.9.7 Java

For JDBC programs, if it's possible for a column in a result set to contain NULL values, it's best to check for them explicitly. The way to do this is to fetch the value and then invoke wasNull( ), which returns true if the column is NULL and false otherwise. For example:

Object obj = rs.getObject (index);
if (rs.wasNull ( ))
{ /* the value's a NULL */ }

The preceding example uses getObject( ), but the principle holds for other getXXX( ) calls as well.

Here's an example that prints each row of a result set as a comma-separated list of values, with each NULL value printed as the string "NULL":

Statement s = conn.createStatement ( );
s.executeQuery ("SELECT name, birth, foods FROM profile");
ResultSet rs = s.getResultSet ( );
ResultSetMetaData md = rs.getMetaData ( );
int ncols = md.getColumnCount ( );
while (rs.next ( )) // loop through rows of result set
{
 for (int i = 0; i < ncols; i++) // loop through columns
 {
 String val = rs.getString (i+1);
 if (i > 0)
 System.out.print (", ");
 if (rs.wasNull ( ))
 System.out.print ("NULL");
 else
 System.out.print (val);
 }
 System.out.println ( );
}
rs.close ( ); // close result set
s.close ( ); // close statement

Using the mysql Client Program

Writing MySQL-Based Programs

Record Selection Techniques

Working with Strings

Working with Dates and Times

Sorting Query Results

Generating Summaries

Modifying Tables with ALTER TABLE

Obtaining and Using Metadata

Importing and Exporting Data

Generating and Using Sequences

Using Multiple Tables

Statistical Techniques

Handling Duplicates

Performing Transactions

Introduction to MySQL on the Web

Incorporating Query Resultsinto Web Pages

Processing Web Input with MySQL

Using MySQL-Based Web Session Management

Appendix A. Obtaining MySQL Software

Appendix B. JSP and Tomcat Primer

Appendix C. References



MySQL Cookbook
MySQL Cookbook
ISBN: 059652708X
EAN: 2147483647
Year: 2005
Pages: 412
Authors: Paul DuBois

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net