Home > Articles

This chapter is from the book

Learning How to Use Operators

Operators are the elements you use inside an expression to articulate how you want specified conditions to retrieve data. Operators fall into six groups: arithmetic, comparison, character, logical, set, and miscellaneous. MySQL utilizes three types of operators: arithmetic, comparison, and logical.

Arithmetic Operators

The arithmetic operators are plus (+), minus (–), divide (/), multiply (*), and modulo (%). The first four are self-explanatory. Modulo returns the integer remainder of a division. Here are two examples:

5 % 2 = 1
6 % 2 = 0

The modulo operator does not work with data types that have decimals, such as Real or Number.

If you place several of these arithmetic operators in an expression without any parentheses, the operators are resolved in this order: multiplication, division, modulo, addition, and subtraction. For example, the expression

2*6+9/3

equals

12 + 3 = 15

However, the expression

2 * (6 + 9) / 3

equals

2 * 15 / 3 = 10

Watch where you put those parentheses! Sometimes the expression does exactly what you tell it to do, rather than what you want it to do. The same holds true for MySQL.

The following sections examine the arithmetic operators in some detail and give you a chance to write some queries.

Plus (+)

You can use the plus sign in several ways. Type the following statement to display the PRICE table:

SQL> SELECT * FROM PRICE;
mysql> select * from price;
ITEM      WHOLESALE
--------------- ---------
TOMATOES       .34
POTATOES       .51
BANANAS        .67
TURNIPS        .45
CHEESE        .89
APPLES        .23
6 rows selected.
+----------+-----------+
| item   | wholesale |
+----------+-----------+
| TOMATOES |   0.34 |
| POTATOES |   0.51 |
| BANANAS |   0.67 |
| TURNIPS |   0.45 |
| CHEESE  |   0.89 |
| APPLES  |   0.23 |
+----------+-----------+
6 rows in set (0.11 sec)

Now type

SQL> SELECT ITEM, WHOLESALE, WHOLESALE + 0.15
   FROM PRICE;
mysql> select item, wholesale, wholesale+.15
  -> from price;

Here the + adds 15 cents to each price to produce the following:

ITEM      WHOLESALE WHOLESALE+0.15
--------------- --------- ---------------
TOMATOES       .34      .49
POTATOES       .51      .66
BANANAS        .67      .82
TURNIPS        .45      .60
CHEESE        .89      1.04
APPLES        .23      .38
6 rows selected.
+----------+-----------+---------------+
| item   | wholesale | wholesale+.15 |
+----------+-----------+---------------+
| TOMATOES |   0.34 |     0.49 |
| POTATOES |   0.51 |     0.66 |
| BANANAS |   0.67 |     0.82 |
| TURNIPS |   0.45 |     0.60 |
| CHEESE  |   0.89 |     1.04 |
| APPLES  |   0.23 |     0.38 |
+----------+-----------+---------------+
6 rows in set (0.00 sec)

What is this last column with the unattractive column heading WHOLESALE+0.15? It's not in the original table. SQL allows you to create a virtual or derived column by combining or modifying existing columns.

Retype the original entry:

SQL> SELECT * FROM PRICE;

The following table results:

ITEM      WHOLESALE
--------------- ---------
TOMATOES       .34
POTATOES       .51
BANANAS        .67
TURNIPS        .45
CHEESE        .89
APPLES        .23
6 rows selected.
+----------+-----------+
| item   | wholesale |
+----------+-----------+
| TOMATOES |   0.34 |
| POTATOES |   0.51 |
| BANANAS |   0.67 |
| TURNIPS |   0.45 |
| CHEESE  |   0.89 |
| APPLES  |   0.23 |
+----------+-----------+
6 rows in set (0.11 sec)

The output confirms that the original data has not been changed and that the column heading WHOLESALE+0.15 is not a permanent part of it. In fact, the column heading is so unattractive that you should do something about it.

Type the following:

SQL> SELECT ITEM, WHOLESALE, (WHOLESALE + 0.15) RETAIL
   FROM PRICE;

Here's the result:

ITEM      WHOLESALE  RETAIL
--------------- ---------  ------
TOMATOES       .34    .49
POTATOES       .51    .66
BANANAS        .67    .82
TURNIPS        .45    .60
CHEESE        .89   1.04
APPLES        .23    .38
6 rows selected.
mysql> select item, wholesale, wholesale+.15 retail
  -> from price;
+----------+-----------+--------+
| item   | wholesale | retail |
+----------+-----------+--------+
| TOMATOES |   0.34 |  0.49 |
| POTATOES |   0.51 |  0.66 |
| BANANAS |   0.67 |  0.82 |
| TURNIPS |   0.45 |  0.60 |
| CHEESE  |   0.89 |  1.04 |
| APPLES  |   0.23 |  0.38 |
+----------+-----------+--------+
6 rows in set (0.01 sec)

This is wonderful! Not only can you create new output columns, but you can also rename them on the fly. You can rename any of the columns using the syntax column_name alias. (Note the space between the column_name and alias.)

For example, the query

SQL> SELECT ITEM PRODUCE, WHOLESALE, WHOLESALE + 0.25 RETAIL
   FROM PRICE;

renames the columns as follows:

PRODUCE     WHOLESALE  RETAIL
--------------- ---------  -------
TOMATOES       .34    .59
POTATOES       .51    .76
BANANAS        .67    .92
TURNIPS        .45    .70
CHEESE        .89   1.14
APPLES        .23    .48
mysql> select item Produce, wholesale, wholesale+0.25
  -> from price;
+----------+-----------+----------------+
| Produce | wholesale | wholesale+0.25 |
+----------+-----------+----------------+
| TOMATOES |   0.34 |      0.59 |
| POTATOES |   0.51 |      0.76 |
| BANANAS |   0.67 |      0.92 |
| TURNIPS |   0.45 |      0.70 |
| CHEESE  |   0.89 |      1.14 |
| APPLES  |   0.23 |      0.48 |
+----------+-----------+----------------+
6 rows in set (0.00 sec)

NOTE

Some implementations of SQL use the syntax <column name = alias>. The preceding example would be written as follows:

SQL> SELECT ITEM = PRODUCE,
   WHOLESALE,
   WHOLESALE + 0.25 = RETAIL,
   FROM PRICE;

NOTE

Check your implementation for the exact syntax.

MySQL allows you to present your column alias in mixed case.

You might be wondering what use aliasing is if you are not using command-line SQL. Fair enough. Have you ever wondered how report builders work? Some day, when you are asked to write a report generator, you'll remember this and not spend weeks reinventing what Dr. Codd and IBM have wrought.

In some implementations of SQL, the plus sign does double duty as a character operator. You'll see that side of the plus sign a little later today.

Minus (-)

Minus also has two uses. First, it can change the sign of a number. You can use the table HILOW to demonstrate this function.

SQL> SELECT * FROM HILOW;
STATE    HIGHTEMP  LOWTEMP
------   --------  -------
CA        -50    120
FL        20    110
LA        15    99
ND        -70    101
NE        -60    100

For example, here's a way to manipulate the data:

SQL> SELECT STATE, -HIGHTEMP LOWS, -LOWTEMP HIGHS
   FROM HILOW;

STATE      LOWS   HIGHS
-----      ----   -----
CA        50   -120
FL        -20   -110
LA        -15    -99
ND        70   -101
NE        60   -100
mysql> select state, -highs Lows, -lows Highs
  -> from hilow;
+-------+------+-------+
| state | Lows | Highs |
+-------+------+-------+
| FL  | -110 |  -20 |
| LA  | -99 |  -15 |
| ND  | -101 |   0 |
| NE  | -100 |   0 |
+-------+------+-------+
4 rows in set (0.04 sec)

NOTE

Notice that the minus sign was reversed on the temperatures.

The second (and obvious) use of the minus sign is to subtract one column from another—for example,

SQL> SELECT STATE,
 2 HIGHTEMP LOWS,
 3 LOWTEMP HIGHS,
 4 (LOWTEMP - HIGHTEMP) DIFFERENCE
 5 FROM HILOW;

STATE      LOWS   HIGHS DIFFERENCE
-----      ----   ----- ----------
CA        -50    120    170
FL        20    110     90
LA        15    99     84
ND        -70    101    171
NE        -60    100    160
mysql> select state,
  -> highs,
  -> lows,
  -> highs - lows Difference
  -> from hilow;
+-------+-------+------+------------+
| state | highs | lows | Difference |
+-------+-------+------+------------+
| FL  |  110 |  20 |     90 |
| LA  |  99 |  15 |     84 |
| ND  |  101 |  0 |    101 |
| NE  |  100 |  0 |    100 |
+-------+-------+------+------------+
4 rows in set (0.25 sec)

Notice the use of aliases to fix the data that was entered incorrectly. This remedy is merely a temporary patch, though, and not a permanent fix. You should see to it that the data is corrected and entered correctly in the future. On Bonus Day 1, "Debugging Your SQL Statements," you'll learn how to correct bad data.

This query not only fixed (at least visually) the incorrect data but also created a new column containing the difference between the highs and lows of each state.

If you accidentally use the minus sign on a character field, you get something like this:

SQL> SELECT -STATE FROM HILOW;

ERROR:
ORA-01722: invalid number
no rows selected

The exact error message varies with implementation. Here is an example using MySQL:

mysql> select -state
  -> from hilow;
+--------+
| -state |
+--------+
|   0 |
|   0 |
|   0 |
|   0 |
+--------+
4 rows in set (0.00 sec)

MySQL evaluated the SELECT statement, but as you can see, the results are rather meaningless.

Divide (/)

The division operator has only the one, obvious meaning. Using the table PRICE, type the following:

SQL> SELECT * FROM PRICE;
ITEM      WHOLESALE
--------    ---------
TOMATOES       .34
POTATOES       .51
BANANAS        .67
TURNIPS        .45
CHEESE        .89
APPLES        .23
6 rows selected.
mysql> select * from price;
+----------+-----------+
| item   | wholesale |
+----------+-----------+
| TOMATOES |   0.34 |
| POTATOES |   0.51 |
| BANANAS |   0.67 |
| TURNIPS |   0.45 |
| CHEESE  |   0.89 |
| APPLES  |   0.23 |
+----------+-----------+

You can show the effects of a two-for-one sale by typing the next statement:

SQL> SELECT ITEM, WHOLESALE, (WHOLESALE/2) SALEPRICE
 2 FROM PRICE;

ITEM      WHOLESALE SALEPRICE
--------------- --------- ---------
TOMATOES       .34    .17
POTATOES       .51   .255
BANANAS        .67   .335
TURNIPS        .45   .225
CHEESE        .89   .445
APPLES        .23   .115
6 rows selected.
mysql> SELECT ITEM, WHOLESALE, WHOLESALE/2 Saleprice
  -> from price;
+----------+-----------+-----------+
| ITEM   | WHOLESALE | Saleprice |
+----------+-----------+-----------+
| TOMATOES |   0.34 |  0.1700 |
| POTATOES |   0.51 |  0.2550 |
| BANANAS |   0.67 |  0.3350 |
| TURNIPS |   0.45 |  0.2250 |
| CHEESE  |   0.89 |  0.4450 |
| APPLES  |   0.23 |  0.1150 |
+----------+-----------+-----------+
6 rows in set (0.26 sec)

The use of division in the preceding SELECT statement is straightforward (except that coming up with half pennies can be tough).

Multiply (*)

The multiplication operator is also straightforward. Again, using the PRICE table, type the following:

SQL> SELECT * FROM PRICE;
ITEM      WHOLESALE
--------------- ---------
TOMATOES       .34
POTATOES       .51
BANANAS        .67
TURNIPS        .45
CHEESE        .89
APPLES        .23
6 rows selected.

The output from this query reflects an across-the-board 10% discount. The actual data in the table has not changed.

SQL> SELECT ITEM, WHOLESALE, WHOLESALE * 0.9 NEWPRICE
   FROM PRICE;

ITEM      WHOLESALE NEWPRICE
--------------- --------- --------
TOMATOES       .34   .306
POTATOES       .51   .459
BANANAS        .67   .603
TURNIPS        .45   .405
CHEESE        .89   .801
APPLES        .23   .207
6 rows selected.
mysql> select Item,
  -> Wholesale, Wholesale * 0.9 "New Price"
  -> from price;
+----------+-----------+-----------+
| Item   | Wholesale | New Price |
+----------+-----------+-----------+
| TOMATOES |   0.34 |   0.31 |
| POTATOES |   0.51 |   0.46 |
| BANANAS |   0.67 |   0.60 |
| TURNIPS |   0.45 |   0.41 |
| CHEESE  |   0.89 |   0.80 |
| APPLES  |   0.23 |   0.21 |
+----------+-----------+-----------+
6 rows in set (0.00 sec)

NOTE

One last thing about aliases. By the use of quotes surrounding your aliases, you can give your column a two-word heading.

These operators enable you to perform powerful calculations in a SELECT statement.

Modulo (%)

The modulo operator returns the integer remainder of the division operation. Using the table REMAINS, type the following:

SQL> SELECT * FROM REMAINS;
NUMERATOR DENOMINATOR
--------- -----------
    10      5
    8      3
    23      9
    40     17
   1024     16
    85     34
6 rows selected.
mysql> select * from remains;
+-----------+-------------+
| numerator | denominator |
+-----------+-------------+
|    10 |      5 |
|     8 |      3 |
|    23 |      9 |
|    40 |     17 |
|   1024 |     16 |
|    85 |     34 |
+-----------+-------------+
6 rows in set (0.43 sec)

You can also create a new output column, REMAINDER, to hold the values of NUMERATOR % DENOMINATOR:

SQL> SELECT NUMERATOR,
   DENOMINATOR,
   NUMERATOR%DENOMINATOR REMAINDER
   FROM REMAINS;

NUMERATOR DENOMINATOR REMAINDER
--------- ----------- ---------
    10      5     0
    8      3     2
    23      9     5
    40     17     6
   1024     16     0
    85     34    17
6 rows selected.
mysql> select numerator, denominator, numerator%denominator
  -> from remains;
+-----------+-------------+-----------------------+
| numerator | denominator | numerator%denominator |
+-----------+-------------+-----------------------+
|    10 |      5 |           0 |
|     8 |      3 |           2 |
|    23 |      9 |           5 |
|    40 |     17 |           6 |
|   1024 |     16 |           0 |
|    85 |     34 |          17 |
+-----------+-------------+-----------------------+
6 rows in set (0.01 sec)

Some implementations of SQL implement modulo as a function called MOD (see Day 4, "Molding Data with Built-in Functions"). The following statement produces results that are identical to the results in the preceding statement:

SQL> SELECT NUMERATOR,
   DENOMINATOR,
   MOD(NUMERATOR,DENOMINATOR) REMAINDER
   FROM REMAINS;
mysql> select numerator, denominator,
  -> mod(numerator,denominator)
  -> from remains;
+-----------+-------------+----------------------------+
| numerator | denominator | mod(numerator,denominator) |
+-----------+-------------+----------------------------+
|    10 |      5 |             0 |
|     8 |      3 |             2 |
|    23 |      9 |             5 |
|    40 |     17 |             6 |
|   1024 |     16 |             0 |
|    85 |     34 |             17 |
+-----------+-------------+----------------------------+
6 rows in set (0.00 sec)

Precedence

Precedence is the order in which an implementation will evaluate different operators in the same expression. This section examines the use of precedence in a SELECT statement. Using the table PRECEDENCE, type the following:

SQL> SELECT * FROM PRECEDENCE;
    N1    N2    N3    N4
 ------- -------- -------- --------
    1     2     3     4
    13    24    35    46
    9     3    23     5
    63     2    45     3
    7     2     1     4
mysql> select * from precedence;
+----+----+----+----+
| n1 | n2 | n3 | n4 |
+----+----+----+----+
| 1 | 2 | 3 | 4 |
| 13 | 24 | 35 | 46 |
| 9 | 3 | 23 | 5 |
| 63 | 2 | 45 | 3 |
| 7 | 2 | 1 | 4 |
+----+----+----+----+
5 rows in set (0.00 sec)

Use the following code segment to test precedence:

SQL> SELECT
 2 N1+N2*N3/N4,
 3 (N1+N2)*N3/N4,
 4 N1+(N2*N3)/N4
 5 FROM PRECEDENCE;

N1+N2*N3/N4 (N1+N2)*N3/N4 N1+(N2*N3)/N4
----------- ------------- -------------
    2.5     2.25      2.5
  31.26087   28.152174   31.26087
    22.8     55.2     22.8
     93      975      93
    7.5     2.25      7.5
mysql> select n1+n2*n3/n4,
  -> (n1+n2)*n3,n4,
  -> n1+(n2*n3)/n4
  -> from precedence;
+-------------+------------+----+---------------+
| n1+n2*n3/n4 | (n1+n2)*n3 | n4 | n1+(n2*n3)/n4 |
+-------------+------------+----+---------------+
|    2.50 |     9 | 4 |     2.50 |
|    31.26 |    1295 | 46 |     31.26 |
|    22.80 |    276 | 5 |     22.80 |
|    93.00 |    2925 | 3 |     93.00 |
|    7.50 |     9 | 4 |     7.50 |
+-------------+------------+----+---------------+
5 rows in set (0.00 sec)

Notice that the first and last columns are identical. If you added a fourth column N1+N2*(N3/N4), its values would also be identical to those of the current first and last columns.

Comparison Operators

True to their name, comparison operators compare expressions and return one of three values: TRUE, FALSE, or UNKNOWN. Wait a minute! Unknown? TRUE and FALSE are self-explanatory, but what is UNKNOWN?

To understand how you could get an UNKNOWN, you need to know a little about the concept of NULL. In database terms, NULL is the absence of data in a field. It does not mean that a column has a zero or a blank in it. A zero or a blank is a value. NULL means nothing is in that field.

If you make a comparison such as Field = 9 and the only acceptable value for Field is NULL, the comparison will come back UNKNOWN. Because UNKNOWN is an uncomfortable condition, most flavors of SQL change UNKNOWN to FALSE and provide a special operator, IS NULL, to test for a NULL condition.

Here's an example of NULL: Suppose an entry in the PRICE table does not contain a value for WHOLESALE. The results of a query might look like this:

SQL> SELECT * FROM PRICE;

ITEM      WHOLESALE
---------    ---------
TOMATOES       .34
POTATOES       .51
BANANAS        .67
TURNIPS        .45
CHEESE        .89
APPLES        .23
ORANGES

Notice that no value appears in the WHOLESALE field position for ORANGES. The value of the field WHOLESALE for ORANGES is NULL. The NULL is noticeable in this case because it is in a numeric column. However, if the NULL appeared in the ITEM column, it would be impossible to tell the difference between NULL and a blank.

Try to find the NULL:

SQL> SELECT *
 2 FROM PRICE
 3 WHERE WHOLESALE IS NULL;

ITEM      WHOLESALE
--------    ---------
ORANGES

As you can see by the output, ORANGES is the only item whose value for -WHOLESALE is NULL, or does not contain a value. What if you use the equal sign (=) instead?

 SELECT *
   FROM PRICE
   WHERE WHOLESALE = NULL;

no rows selected

You wouldn't find anything because the comparison WHOLESALE = NULL returned a FALSE—the result was unknown. It would be more appropriate to use an IS NULL instead of =, changing the WHERE statement to WHERE WHOLESALE IS NULL. In this case, you would get all the rows where a NULL existed.

This example also illustrates both the use of the most common comparison operator (=) and the playground of all comparison operators, the WHERE clause. You already know about the WHERE clause, so here's a brief look at the equal sign.

Equal Sign (=)

Earlier today you saw how some implementations of SQL use the equal sign in the SELECT clause to assign an alias. In the WHERE clause, the equal sign is the most commonly used comparison operator. Used alone, the equal sign is a very convenient way of selecting one value out of many. Try this:

SQL> SELECT * FROM FRIENDS;
LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- --------
BUNDY      AL          100 555-1111 IL 22333
MEZA      AL          200 555-2222 UK
MERRICK     BUD          300 555-6666 CO 80212
MAST      JD          381 555-6767 LA 23456
BULHER     FERRIS        345 555-3223 IL 23332

Let's find JD's row. (On a short list this task appears trivial, but you may have more friends than we do—or you may have a list with thousands of records.)

SQL> SELECT *
   FROM FRIENDS
   WHERE FIRSTNAME = 'JD';

LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- -- -----
MAST      JD          381 555-6767 LA 23456
mysql> select * from friends
  -> where firstname = 'JD';
+----------+-----------+----------+----------+----+-------+
| lastname | firstname | areacode | phone  | st | zip  |
+----------+-----------+----------+----------+----+-------+
| MAST   | JD    |   381 | 555-6767 | LA | 23456 |
+----------+-----------+----------+----------+----+-------+
1 row in set (0.37 sec)

We got the result that we expected. Try this:

SQL> SELECT *
   FROM FRIENDS
   WHERE FIRSTNAME = 'AL';

LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- -- -----
BUNDY      AL          100 555-1111 IL 22333
MEZA      AL          200 555-2222 UK

NOTE

Here you see that = can pull in multiple records. Notice that ZIP is blank on the second record. ZIP is a character field (you learn how to create and populate tables on Day 9, "Creating and Maintaining Tables"), and in this particular record, the NULL demonstrates that a NULL in a character field is impossible to differentiate from a blank field.

Here's another very important lesson concerning case sensitivity:

SQL> SELECT FIRSTNAME FROM FRIENDS
   WHERE FIRSTNAME = 'BUD';

FIRSTNAME
---------------
BUD
1 row selected.
mysql> select firstname from friends where firstname = 'BUD';
+-----------+
| firstname |
+-----------+
| BUD    |
+-----------+
1 row in set (0.00 sec)

Now try this:

SQL> select FIRSTNAME from friends
   where firstname = 'Bud';

no rows selected.
mysql> select firstname
  -> from friends
  -> where firstname = 'bud';
+-----------+
| firstname |
+-----------+
| BUD    |
+-----------+
1 row in set (0.01 sec)

Even though SQL syntax is not case sensitive, data within it is, at least in some implementations. As you can see in the preceding examples, data stored in an Oracle database (SQL*Plus) is case sensitive while the MySQL example demonstrates the opposite.

Most companies prefer to store data in uppercase to provide data consistency. I recommend that you always store data either in all uppercase or in all lowercase, regardless of what type or database you are working in. Mixing case might create difficulties when you try to retrieve accurate data through comparisons in the WHERE clause.

Greater Than (>) and Greater Than or Equal To (>=)

The greater than operator (>) works like this:

SQL> SELECT *
   FROM FRIENDS
   WHERE AREACODE > 300;
LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- -- ------
MAST      JD          381 555-6767 LA 23456
BULHER     FERRIS        345 555-3223 IL 23332

This example found all the area codes greater than (but not including) 300. To include 300, type this:

SQL> SELECT *
 2 FROM FRIENDS
 3 WHERE AREACODE >= 300;

LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- -- -----
MERRICK     BUD          300 555-6666 CO 80212
MAST      JD          381 555-6767 LA 23456
BULHER     FERRIS        345 555-3223 IL 23332
mysql> select * from friends
  -> where areacode >= 300;
+----------+-----------+----------+----------+----+-------+
| lastname | firstname | areacode | phone  | st | zip  |
+----------+-----------+----------+----------+----+-------+
| MERRICK | BUD    |   300 | 555-6666 | CO | 80212 |
| MAST   | JD    |   381 | 555-6767 | LA | 23456 |
| BULHER  | FERRIS  |   345 | 555-3223 | IL | 23332 |
+----------+-----------+----------+----------+----+-------+
3 rows in set (0.34 sec)

With this change you get area codes starting at 300 and going up. You could achieve the same results with the statement AREACODE > 299.

NOTE

Notice that no quotes surround 300 in this SQL statement. Number-defined fields do not require quotes.

Less Than (<) and Less Than or Equal To (<=)

As you might expect, these comparison operators work the same way as > and >= work, only in reverse:

SQL> SELECT *
 2 FROM FRIENDS
 3 WHERE ST < 'LA';
LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- -- -----
BUNDY      AL          100 555-1111 IL 22333
MERRICK     BUD          300 555-6666 CO 80212
BULHER     FERRIS        345 555-3223 IL 23332
mysql> select * from friends where st < 'LA';
+----------+-----------+----------+----------+----+-------+
| lastname | firstname | areacode | phone  | st | zip  |
+----------+-----------+----------+----------+----+-------+
| BUNDY  | AL    |   100 | 555-1111 | IL | 22333 |
| MERRICK | BUD    |   300 | 555-6666 | CO | 80212 |
| BULHER  | FERRIS  |   345 | 555-3223 | IL | 23332 |
+----------+-----------+----------+----------+----+-------+
3 rows in set (0.00 sec)

NOTE

In an Oracle database, if the column has only two characters, the column name is shortened to two characters in the returned rows. If the column name had been COWS, it would come out CO. The widths of AREACODE and PHONE are wider than their column names, so they are not truncated.

Wait a minute. Did you just use < on a character field? Of course you did. You can use any of these operators on any data type. The result varies by data type. For example, use lowercase in the following state search:

SQL> SELECT *
 2 FROM FRIENDS
 3 WHERE STATE < 'la';

LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- -- -----
BUNDY      AL          100 555-1111 IL 22333
MEZA      AL          200 555-2222 UK
MERRICK     BUD          300 555-6666 CO 80212
MAST      JD          381 555-6767 LA 23456
BULHER     FERRIS        345 555-3223 IL 23332
mysql> select * from friends where st < 'la';
+----------+-----------+----------+----------+----+-------+
| lastname | firstname | areacode | phone  | st | zip  |
+----------+-----------+----------+----------+----+-------+
| BUNDY  | AL    |   100 | 555-1111 | IL | 22333 |
| MEZA   | AL    |   200 | 555-2222 | UK |    |
| MERRICK | BUD    |   300 | 555-6666 | CO | 80212 |
| MAST   | JD    |   381 | 555-6767 | LA | 23456 |
| BULHER  | FERRIS  |   345 | 555-3223 | IL | 23332 |
+----------+-----------+----------+----------+----+-------+
3 rows in set (0.00 sec)

Uppercase is usually sorted before lowercase; therefore, the uppercase codes returned are less than 'la'. Again, to be safe, check your implementation.

TIP

To be sure of how these operators will behave, check your language tables. Most PC implementations use the ASCII tables.

To include the state of Louisiana in the original search, type

SQL> SELECT *
 2 FROM FRIENDS
 3 WHERE STATE <= 'LA';

LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- -- -----
BUNDY      AL          100 555-1111 IL 22333
MERRICK     BUD          300 555-6666 CO 80212
MAST      JD          381 555-6767 LA 23456
BULHER     FERRIS        345 555-3223 IL 23332
mysql> select * from friends where st <= 'LA';
+----------+-----------+----------+----------+----+-------+
| lastname | firstname | areacode | phone  | st | zip  |
+----------+-----------+----------+----------+----+-------+
| BUNDY  | AL    |   100 | 555-1111 | IL | 22333 |
| MERRICK | BUD    |   300 | 555-6666 | CO | 80212 |
| MAST   | JD    |   381 | 555-6767 | LA | 23456 |
| BULHER  | FERRIS  |   345 | 555-3223 | IL | 23332 |
+----------+-----------+----------+----------+----+-------+
4 rows in set (0.00 sec)

Inequalities (< > or !=)

When you need to find everything except for certain data, use the inequality symbol, which can be either < > or !=, depending on your SQL implementation. For example, to find everyone who is not AL, type this:

SQL> SELECT *
 2 FROM FRIENDS
 3 WHERE FIRSTNAME <> 'AL';
LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- -- -----
MERRICK     BUD          300 555-6666 CO 80212
MAST      JD          381 555-6767 LA 23456
BULHER     FERRIS        345 555-3223 IL 23332
mysql> select * from friends where st <> 'AL';
+----------+-----------+----------+----------+----+-------+
| lastname | firstname | areacode | phone  | st | zip  |
+----------+-----------+----------+----------+----+-------+
| BUNDY  | AL    |   100 | 555-1111 | IL | 22333 |
| MERRICK | BUD    |   300 | 555-6666 | CO | 80212 |
| MAST   | JD    |   381 | 555-6767 | LA | 23456 |
| BULHER  | FERRIS  |   345 | 555-3223 | IL | 23332 |
+----------+-----------+----------+----------+----+-------+
4 rows in set (0.00 sec)

To find everyone not living in California, type this:

SQL> SELECT *
 2 FROM FRIENDS
 3 WHERE STATE != 'CA';

LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- -- -----
BUNDY      AL          100 555-1111 IL 22333
MEZA      AL          200 555-2222 UK
MERRICK     BUD          300 555-6666 CO 80212
MAST      JD          381 555-6767 LA 23456
BULHER     FERRIS        345 555-3223 IL 23332
mysql> select * from friends where st != 'CA';
+----------+-----------+----------+----------+----+-------+
| lastname | firstname | areacode | phone  | st | zip  |
+----------+-----------+----------+----------+----+-------+
| BUNDY  | AL    |   100 | 555-1111 | IL | 22333 |
| MERRICK | BUD    |   300 | 555-6666 | CO | 80212 |
| MAST   | JD    |   381 | 555-6767 | LA | 23456 |
| BULHER  | FERRIS  |   345 | 555-3223 | IL | 23332 |
+----------+-----------+----------+----------+----+-------+
4 rows in set (0.00 sec)

NOTE

Notice that both symbols, <> and !=, can express "not equal" in the two implementations we have shown you.

Character Operators

You can use character operators to manipulate the way character strings are represented, both in the output of data and in the process of placing conditions on data to be retrieved. This section describes two character operators: the LIKE operator and the || operator, the latter of which conveys the concept of character concatenation.

I Want to Be Like LIKE

What if you wanted to select parts of a database that fit a pattern but weren't quite exact matches? You could use the equal sign and run through all the possible cases, but that process would be boring and time consuming. Instead, you can use LIKE. Consider the following:

SQL> SELECT * FROM PARTS;
NAME      LOCATION    PARTNUMBER
-----------   -----------   ----------
APPENDIX    MID-STOMACH       1
ADAMS APPLE   THROAT          2
HEART      CHEST          3
SPINE      BACK           4
ANVIL      EAR           5
KIDNEY     MID-BACK         6

How can you find all the parts located in the back? A quick visual inspection of this simple table shows that it has two parts, but unfortunately the locations have slightly different names. Try this:

SQL> SELECT *
 2 FROM PARTS
 3 WHERE LOCATION LIKE '%BACK%';

NAME      LOCATION    PARTNUMBER
-------     --------    ----------
SPINE      BACK           4
KIDNEY     MID-BACK         6

You can see the use of the percent sign (%) in the statement after LIKE. When used inside a LIKE expression, % is a wildcard. What you asked for was any occurrence of BACK in the column location. If you queried

SQL> SELECT *
   FROM PARTS
   WHERE LOCATION LIKE 'BACK%';

you would get any occurrence that started with BACK:

NAME      LOCATION    PARTNUMBER
-----      --------    ----------
SPINE      BACK           4
mysql> select * from parts where location like 'BACK%';
+-------+----------+------------+
| name | location | partnumber |
+-------+----------+------------+
| SPINE | BACK   |     4 |
+-------+----------+------------+
1 row in set (0.00 sec)

If you queried

SQL> SELECT *
   FROM PARTS
   WHERE NAME LIKE 'A%';

you would get any name that starts with A:

NAME      LOCATION    PARTNUMBER
-----------   -----------   ----------
APPENDIX    MID-STOMACH       1
ADAMS APPLE   THROAT          2
ANVIL      EAR           5

Is LIKE case sensitive in both Oracle and MySQL? Try the next query to find out.

SQL> SELECT *
   FROM PARTS
   WHERE NAME LIKE 'a%';

no rows selected
mysql> select * from parts where name like 'a%';
+-------------+-------------+------------+
| name    | location  | partnumber |
+-------------+-------------+------------+
| APPENDIX  | MID-STOMACH |     1 |
| ADAMS APPLE | THROAT   |     2 |
| ANVIL    | EAR     |     5 |
+-------------+-------------+------------+
3 rows in set (0.00 sec)

The answer is yes in Oracle and no in MySQL. References to data are dependent upon the implementation you are working with.

What if you want to find data that matches all but one character in a certain pattern? In this case you could use a different type of wildcard: the underscore.

Underscore (_)

The underscore is the single-character wildcard. Using a modified version of the table FRIENDS, type this:

SQL> SELECT * FROM FRIENDS;
LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- -- -----
BUNDY      AL          100 555-1111 IL 22333
MEZA      AL          200 555-2222 UK
MERRICK     BUD          300 555-6666 CO 80212
MAST      JD          381 555-6767 LA 23456
BULHER     FERRIS        345 555-3223 IL 23332
PERKINS     ALTON         911 555-3116 CA 95633
BOSS      SIR          204 555-2345 CT 95633

To find all the records where STATE starts with C, type the following:

SQL> SELECT *
 2 FROM FRIENDS
 3 WHERE ST LIKE 'C_';

LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- -- -----
MERRICK     BUD          300 555-6666 CO 80212
PERKINS     ALTON         911 555-3116 CA 95633
BOSS      SIR          204 555-2345 CT 95633
mysql> select * from friends where st like 'C_';
+----------+-----------+----------+----------+----+-------+
| lastname | firstname | areacode | phone  | st | zip  |
+----------+-----------+----------+----------+----+-------+
| MERRICK | BUD    |   300 | 555-6666 | CO | 80212 |
| PERKINS | ALTON   |   911 | 555-3116 | CA | 95633 |
| BOSS   | SIR    |   204 | 555-2345 | CT | 95633 |
+----------+-----------+----------+----------+----+-------+
1 row in set (0.00 sec)

You can use several underscores in a statement:

SQL> SELECT *
 2 FROM FRIENDS
 3 WHERE PHONE LIKE'555-6_6_';

LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- -- -----
MERRICK     BUD          300 555-6666 CO 80212
MAST      JD          381 555-6767 LA 23456

The previous statement could also be written as follows:

SQL> SELECT *
 2 FROM FRIENDS
 3 WHERE PHONE LIKE '555-6%';

LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- -- -----
MERRICK     BUD          300 555-6666 CO 80212
MAST      JD          381 555-6767 LA 23456

Notice that the results are identical. These two wildcards can be combined. The next example finds all records with L as the second character:

SQL> SELECT *
 2 FROM FRIENDS
 3 WHERE FIRSTNAME LIKE '_L%';

LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- -- -----
BUNDY      AL          100 555-1111 IL 22333
MEZA      AL          200 555-2222 UK
PERKINS     ALTON         911 555-3116 CA 95633

Concatenation (||)

The || (double pipe) symbol concatenates two strings. Try this:

SQL> SELECT FIRSTNAME || LASTNAME ENTIRENAME
 2 FROM FRIENDS;

ENTIRENAME
----------------------
AL       BUNDY
AL       MEZA
BUD      MERRICK
JD       MAST
FERRIS     BULHER
ALTON     PERKINS
SIR      BOSS
7 rows selected.

Notice that || is used instead of +. If you use + to try to concatenate the strings, -the SQL interpreter used for this example (Personal Oracle) returns the following error:

SQL> SELECT FIRSTNAME + LASTNAME ENTIRENAME
   FROM FRIENDS;

ERROR:
ORA-01722: invalid number

It is looking for two numbers to add and throws the error invalid number when it doesn't find any.

NOTE

Some implementations of SQL use the plus sign to concatenate strings. Check your implementation.

MySQL can be set up to allow the || for concatenation; however, this is not the default when MySQL is installed. concat() is the default. Any number of variables may be passed to the function concat() and it is quite easy to use. Should you desire to change the parameters in MySQL to allow the use of the || for concatenation, please research the documentation provided with MySQL on the subject first.

mysql> select concat(firstname," ",lastname)Entirename from friends;
+---------------+
| Entirename  |
+---------------+
| AL BUNDY   |
| BUD MERRICK  |
| JD MAST    |
| FERRIS BULHER |
+---------------+
4 rows in set (0.00 sec)

Here's a more practical example using concatenation:

SQL> SELECT LASTNAME || ',' || FIRSTNAME NAME
   FROM FRIENDS;

NAME
----------------------------------------------
BUNDY  , AL
MEZA   , AL
MERRICK , BUD
MAST   , JD
BULHER  , FERRIS
PERKINS , ALTON
BOSS   , SIR
7 rows selected.
mysql> select concat(lastname,","," ",firstname)Name from friends;
+----------------+
| Name      |
+----------------+
| BUNDY, AL   |
| MEZA, AL    |

| MERRICK, BUD  |
| MAST, JD    |
| BULHER, FERRIS |
| PERKINS, ALTON |
| BOSS, SIR   |

+----------------+
4 rows in set (0.00 sec)

The Oracle statement inserted a comma between the last name and the first name. This was done because Oracle (and other implementations) accounts for the entire length that a column may be when it concatenates to the another string. This creates a natural spacing between the values of the columns/strings. The MySQL statement inserted a comma and a space between the two columns. MySQL automatically runs the values of the columns/strings into one, thus any "natural" spacing between the values is lost.

NOTE

More on this space issue: Notice the extra spaces between the first name and the last name in the Oracle examples. These spaces are actually part of the data. With certain data types, spaces are right-padded to values less than the total length allocated for a field. See your implementation. Data types will be discussed on Day 9.

So far you have performed the comparisons one at a time. That method is fine for some problems, but what if you need to find all the people at work with last names starting with P who have less than three days of vacation time? Logical operators can help in this case.

Logical Operators

Logical operators separate two or more conditions in the WHERE clause of a SQL statement.

Vacation time is always a hot topic around the workplace. Say you designed a table called VACATION for the accounting department:

SQL> SELECT * FROM VACATION;

LASTNAME    EMPLOYEENUM   YEARS LEAVETAKEN
--------------- -----------   ----- ----------
ABLE          101     2     4
BAKER          104     5     23
BLEDSOE         107     8     45
BOLIVAR         233     4     80
BOLD          210    15    100
COSTALES        211    10     78
6 rows selected.

Suppose your company gives each employee 12 days of leave each year. Using what you have learned and a logical operator, find all the employees whose name starts with B and who have more than 50 days of leave coming.

SQL> SELECT LASTNAME,
 2 YEARS * 12 - LEAVETAKEN REMAINING
 3 FROM VACATION
 4 WHERE LASTNAME LIKE 'B%'
 5 AND
 6 YEARS * 12 - LEAVETAKEN > 50;

LASTNAME    REMAINING
--------    ---------
BLEDSOE        51
BOLD          80
mysql> select lastname,
  -> years*12 - leavetaken remaining
  -> from vacation
  -> where lastname like 'B%'
  -> and years*12 - leavetaken > 50;
+----------+-----------+
| lastname | remaining |
+----------+-----------+
| BLEDSOE |    51 |
| BOLD   |    80 |
+----------+-----------+
2 rows in set (0.00 sec)

This query is the most complicated you have done to date. The SELECT clause (lines 1 and 2) uses arithmetic operators to determine how many days of leave each employee has remaining. The normal precedence computes YEARS * 12 - LEAVETAKEN. (A clearer approach would be to write (YEARS * 12) - LEAVETAKEN.)

LIKE is used in line 4 with the wildcard % to find all the B names. Line 6 uses the > to find all occurrences greater than 50.

The new element is on line 5. You used the logical operator AND to ensure that you found records that met the criteria in lines 4 and 6.

AND

AND requires that both expressions on either side be true to return TRUE. If either expression is false, AND returns FALSE. For example, to find out which employees have been with the company for 5 or fewer years and have taken more than 20 days leave, try this:

SQL> SELECT LASTNAME
 2 FROM VACATION
 3 WHERE YEARS <= 5
 4 AND
 5 LEAVETAKEN > 20 ;

LASTNAME
--------
BAKER
BOLIVAR
mysql> select lastname from vacation
  -> where years <= 5
  -> and leavetaken > 20;
+----------+
| lastname |
+----------+
| BAKER  |
| BOLIVAR |
+----------+
2 rows in set (0.00 sec)

If you want to know which employees have been with the company for 5 years or more and have taken less than 50 percent of their leave, you could write:

SQL> SELECT LASTNAME WORKAHOLICS
 2 FROM VACATION
 3 WHERE YEARS >= 5
 4 AND
 5 ((YEARS *12)-LEAVETAKEN)/(YEARS * 12) < 0.50;

WORKAHOLICS
-----------
BAKER
BLEDSOE
mysql> select lastname Workaholics
  -> from vacation
  -> where years >= 5
  -> and ((years * 12) - leavetaken) / (years * 12) < 0.50;
+-------------+
| Workaholics |
+-------------+
| BOLD    |
| COSTALES  |
+-------------+
2 rows in set (0.00 sec)

Check these people for burnout. Also check out how we used the AND to combine these two conditions.

OR

You can also use OR to sum up a series of conditions. If any of the comparisons are true, OR returns TRUE. To illustrate the difference, run the last query with OR instead of with AND:

SQL> SELECT LASTNAME WORKAHOLICS
 2 FROM VACATION
 3 WHERE YEARS >= 5
 4 OR
 5 ((YEARS *12)-LEAVETAKEN)/(YEARS * 12) >= 0.50;

WORKAHOLICS
-----------
ABLE
BAKER
BLEDSOE
BOLD
COSTALES
mysql> select lastname
  -> from vacation
  -> where years >= 5
  -> OR ((years*12)-leavetaken)/(years*12) < 0.50;
+----------+
| lastname |
+----------+
| BAKER  |
| BLEDSOE |
| BOLD   |
| COSTALES |
+----------+
5 rows in set (0.00 sec)

The original names are still in the list, but you have three new entries (who would probably resent being called workaholics). These three new names made the list because they satisfied one of the conditions. OR requires only that one of the conditions be true in order for data to be returned.

NOT

NOT means just that. If the condition it applies to evaluates to TRUE, NOT makes it FALSE. If the condition after the NOT is FALSE, it becomes TRUE. For example, the following SELECT returns the only two names not beginning with B in the table:

SQL> SELECT *
 2 FROM VACATION
 3 WHERE LASTNAME NOT LIKE 'B%';

LASTNAME    EMPLOYEENUM   YEARS LEAVETAKEN
--------    -----------   ----- ----------
ABLE          101     2     4
COSTALES        211    10     78
mysql> select * from vacation
  -> where lastname not like 'B%';
+----------+-------------+-------+------------+
| lastname | employeenum | years | leavetaken |
+----------+-------------+-------+------------+
| ABLE   |     101 |   2 |     4 |
| COSTALES |     211 |  10 |     78 |
+----------+-------------+-------+------------+
2 rows in set (0.00 sec)

NOT can also be used with the operator IS when applied to NULL. Recall the PRICE table where we put a NULL value in the WHOLESALE column opposite the item ORANGES.

SQL> SELECT * FROM PRICE;

ITEM      WHOLESALE
--------------- ---------
TOMATOES       .34
POTATOES       .51
BANANAS        .67
TURNIPS        .45
CHEESE        .89
APPLES        .23
ORANGES
7 rows selected.

To find the non-NULL items, type this:

SQL> SELECT *
 2 FROM PRICE
 3 WHERE WHOLESALE IS NOT NULL;

ITEM      WHOLESALE
--------------- ---------
TOMATOES       .34
POTATOES       .51
BANANAS        .67
TURNIPS        .45
CHEESE        .89
APPLES        .23
6 rows selected.

Set Operators

On Day 1 you learned that SQL is based on the theory of sets. The following sections examine set operators. Set operators are used to combine different sets of data returned by different queries into one query, and ultimately, one data set. There are various set operators available in SQL that allow you to combine different data sets to meet your data processing needs.

UNION and UNION ALL

UNION returns the results of two queries minus the duplicate rows. As stated previously, this text uses MySQL version 3.23.49, which is the most recent, stable version of MySQL. Starting with MySQL version 4.0, there will be support for unions. Examples and discussion of unions will be strictly in Oracle. The following two tables represent the rosters of teams:

SQL> SELECT * FROM FOOTBALL;

NAME
----------------
ABLE
BRAVO
CHARLIE
DECON
EXITOR
FUBAR
GOOBER
7 rows selected.
SQL> SELECT * FROM SOFTBALL;

NAME
-----------------
ABLE
BAKER
CHARLIE
DEAN
EXITOR
FALCONER
GOOBER
7 rows selected.

How many different people play on one team or another?

SQL> SELECT NAME FROM SOFTBALL
 2 UNION
 3 SELECT NAME FROM FOOTBALL;

NAME
----------------
ABLE
BAKER
BRAVO
CHARLIE
DEAN
DECON
EXITOR
FALCONER
FUBAR
GOOBER
10 rows selected.

UNION returns 10 distinct names from the two lists. How many names are on both lists (including duplicates)?

SQL> SELECT NAME FROM SOFTBALL
 2 UNION ALL
 3 SELECT NAME FROM FOOTBALL;

NAME
----------------
ABLE
BAKER
CHARLIE
DEAN
EXITOR
FALCONER
GOOBER
ABLE
BRAVO
CHARLIE
DECON
EXITOR
FUBAR
GOOBER
14 rows selected.

The combined list—courtesy of the UNION ALL statement—has 14 names. UNION ALL works just like UNION except that it does not eliminate duplicates. Now show me a list of players who are on both teams. You can't do that with UNION—you need to learn INTERSECT.

INTERSECT

INTERSECT returns only the rows found by both queries. The next SELECT statement shows the list of players who play on both teams:

SQL> SELECT * FROM FOOTBALL
 2 INTERSECT
 3 SELECT * FROM SOFTBALL;

NAME
----------------
ABLE
CHARLIE
EXITOR
GOOBER

In this example, INTERSECT finds the short list of players who are on both teams by combining the results of the two SELECT statements.

MINUS (Difference)

MINUS returns the rows from the first query that were not present in the second. For example:

SQL> SELECT * FROM FOOTBALL
 2 MINUS
 3 SELECT * FROM SOFTBALL;

NAME
-----------------
BRAVO
DECON
FUBAR

The preceding query shows the three football players who are not on the softball team. If you reverse the order, you get the three softball players who aren't on the football team:

SQL> SELECT * FROM SOFTBALL
 2 MINUS
 3 SELECT * FROM FOOTBALL;

NAME
------------------
BAKER
DEAN
FALCONER

Miscellaneous Operators: IN and BETWEEN

The two operators IN and BETWEEN provide a shorthand for functions you already know how to do. If you wanted to find friends in Colorado, California, and Louisiana, you could type the following:

SQL> SELECT *
 2 FROM FRIENDS
 3 WHERE STATE= 'CA'
 4 OR
 5 STATE ='CO'
 6 OR
 7 STATE = 'LA';

LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- -- -----
MERRICK     BUD          300 555-6666 CO 80212
MAST      JD          381 555-6767 LA 23456
PERKINS     ALTON         911 555-3116 CA 95633

Or you could type this:

SQL> SELECT *
 2 FROM FRIENDS
 3 WHERE ST IN('CA','CO','LA');

LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- -- -----
MERRICK     BUD          300 555-6666 CO 80212
MAST      JD          381 555-6767 LA 23456
PERKINS     ALTON         911 555-3116 CA 95633
mysql> select * from friends
  -> where st in ('CA','CO','LA');
+----------+-----------+----------+----------+----+-------+
| lastname | firstname | areacode | phone  | st | zip  |
+----------+-----------+----------+----------+----+-------+
| MERRICK | BUD    |   300 | 555-6666 | CO | 80212 |
| MAST   | JD    |   381 | 555-6767 | LA | 23456 |
| PERKINS | ALTON   |   911 | 555-3116 | CA | 95633 |
+----------+-----------+----------+----------+----+-------+
2 rows in set (0.20 sec)

The second example is shorter and more readable than the first. You never know when you might have to go back and work on something you wrote months ago. IN also works with numbers. Consider the following, where the column AREACODE is a number:

SQL> SELECT *
 2 FROM FRIENDS
 3 WHERE AREACODE IN(100,381,204);

LASTNAME    FIRSTNAME    AREACODE PHONE  ST ZIP
--------    ---------    -------- -------- -- -----
BUNDY      AL          100 555-1111 IL 22333
MAST      JD          381 555-6767 LA 23456
BOSS      SIR          204 555-2345 CT 95633

If you needed a range of data from the PRICE table, you could write the following:

SQL> SELECT *
 2  FROM PRICE
 3  WHERE WHOLESALE > 0.25
 4  AND
 5  WHOLESALE < 0.75;

ITEM      WHOLESALE
--------    ---------
TOMATOES       .34
POTATOES       .51
BANANAS        .67
TURNIPS        .45

Or using BETWEEN, you would write this:

SQL> SELECT *
 2 FROM PRICE
 3 WHERE WHOLESALE BETWEEN 0.25 AND 0.75;

ITEM      WHOLESALE
--------    ---------
TOMATOES       .34
POTATOES       .51
BANANAS        .67
TURNIPS        .45
mysql> select * from price
  -> where wholesale between .25 and .75;
+----------+-----------+
| item   | wholesale |
+----------+-----------+
| TOMATOES |   0.34 |
| POTATOES |   0.51 |
| BANANAS |   0.67 |
| TURNIPS |   0.45 |
+----------+-----------+
4 rows in set (0.08 sec)

Again, the second example is a cleaner, more readable solution than the first.

NOTE

If a WHOLESALE value of 0.25 existed in the PRICE table, that record would have been retrieved also. Parameters used with BETWEEN are inclusive.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020