Sams Teach Yourself MySQL in 10 Minutes
Sams Teach Yourself MySQL in 10 Minutes
By Chris Newman
...............................................
Publisher: Sams
Pub Date: May 09, 2006
Print ISBN-10: 0-672-32863-1
Print ISBN-13: 978-0-672-32863-3
Pages: 288
Sams Teach Yourself MySQL in 10 Minutes provides a no-fluff, just-the-answers guide to building
and managing MySQL databases. It is carefully organized and thoughtfully written to provide just
the information that you need in order to gain a rapid working knowledge of MySQL. Get up to
speed quickly with Sams Teach Yourself MySQL in 10 Minutes.
Sams Teach Yourself MySQL® in 10 Minutes
By Chris Newman
...............................................
Publisher: Sams
Pub Date: May 09, 2006
Print ISBN-10: 0-672-32863-1
Print ISBN-13: 978-0-672-32863-3
Pages: 288
Copyright
About the Author
Introduction
Part 1: MySQL Foundations
Lesson 1. Introducing MySQL
Database Basics
MySQL Components
Summary
Lesson 2. Using MySQL
The mysql Client
Executing SQL Statements
Creating the Sample Tables
Summary
Part 2: Getting Started with SQL
Lesson 3. Retrieving Data
The SELECT Statement
Summary
Lesson 4. Filtering and Sorting Data
The WHERE Clause
The ORDER BY Clause
Summary
Lesson 5. Advanced Data Filtering
Combining WHERE Clauses
Limiting the Number of Rows Returned
Summary
Lesson 6. Numeric Operators and Functions
Numeric Operators
Numeric Functions
Conditional Functions
Summary
Lesson 7. String Operators and Functions
Using Operators with Strings
String Functions
Summary
Lesson 8. Date Operators and Functions
Date Operators
Date Functions
Summary
Lesson 9. Summarizing Data
Aggregate Functions
Grouping Data
Filtering Summary Data
Summary
Part 3: Advance SQL
Lesson 10. Using Subqueries
Understanding Subqueries
Summary
Lesson 11. Joining Tables
Understanding Joins
Summary
Lesson 12. Creating Advanced Joins
The JOIN Keyword
Inner Joins
Joining Multiple Tables
Cross Joins
Self-Joins
Natural Joins
Outer Joins
Summary
Lesson 13. Combining Queries
Understanding Combined Queries
Other Compound Operations
Using Temporary Tables
Summary
Part 4: Creating a New Database
Lesson 14. Creating and Modifying Tables
Creating a New Database
Character Sets and Collations
Altering a Database
Dropping a Database
Managing Tables
Temporary Tables
Using a Query to Create a Table
Storage Engines
Altering Tables
Dropping Tables
Summary
Lesson 15. Working with Data
The INSERT Statement
The DELETE Statement
The UPDATE Statement
The REPLACE Statement
Loading Data from a File
Why Use Transactions?
Transactions in MySQL
Autocommit Mode
Rolling Back a Transaction
Summary
Lesson 16. Designing Your Database
Relationships
Normalization
Naming Tables and Columns
Data Types
CHAR and VARCHAR
Summary
Lesson 17. Keys and Indexes
Understanding Keys and Indexes
Using Indexes in MySQL
Summary
Lesson 18. Managing User Access
Understanding MySQL Authentication
User Management
Using Wildcards
Summary
Part 5: New Features in MySQL 5.0
Lesson 19. Views
Understanding Views
Summary
Lesson 20. Stored Routines
Understanding Stored Routines
Summary
Lesson 21. Triggers
Understanding Triggers
Using Triggers
Summary
Part 6: Interfacing with MySQL
Lesson 22. Using ODBC
Understanding ODBC
Connecting to MyODBC
Summary
Lesson 23. Using MySQL with C
The C Language API
Summary
Lesson 24. Using MySQL with PHP
Using the mysql API
Using the mysqli API
Summary
Lesson 25. Using MySQL with Perl
The Perl DBI
Using the MySQL DBD
Summary
Part 7: Appendix
Appendix A. Installing MySQL
Obtaining MySQL
Linux/UNIX Installation
Windows Installation
Appendix B. Sample Table Scripts
Index
Copyright
Sams Teach Yourself MySQL® in 10 Minutes
All rights reserved. No part of this book shall be reproduced, stored in a retrieval system, or
transmitted by any means, electronic, mechanical, photocopying, recording, or otherwise, without
written permission from the publisher. No patent liability is assumed with respect to the use of the
information contained herein. Although every precaution has been taken in the preparation of this
book, the publisher and author assume no responsibility for errors or omissions. Nor is any liability
assumed for damages resulting from the use of the information contained herein.
09 08 07 06 4 3 2 1
Trademarks
All terms mentioned in this book that are known to be trademarks or service marks have been
appropriately capitalized. Sams Publishing cannot attest to the accuracy of this information. Use of a
term in this book should not be regarded as affecting the validity of any trademark or service mark.
Bulk Sales
Sams Publishing offers excellent discounts on this book when ordered in quantity for bulk purchases
or special sales. For more information, please contact
corpsales@pearsontechgroup.com
International Sales
international@pearsoned.com
ACQUISITIONS EDITOR
Shelley Johnston
DEVELOPMENT EDITOR
Damon Jordan
MANAGING EDITOR
Charlotte Clapp
P ROJECT EDITOR
Andy Beaster
COPY EDITOR
Krista Hansing
INDEXER
Juli Bess
P ROOFREADER
Kathy Bidwell
TECHNICAL EDITOR
Adam DeFields
P UBLISHING
COORDINATOR
Vanessa Evans
INTERIOR DESIGNER
Gary Adair
COVER DESIGNER
Aren Howell
P AGE LAYOUT
Nonie Ratcliff
About the Author
Chris Newman is a consultant programmer who specializes in database development with an
Internet twist. He has extensive commercial experience in using PHP to integrate various database
systems, and he has produced a wide range of applications for an international client base.
A graduate of Keele University, Chris lives in Stoke-on-Trent, England, where he runs Lightwood
Consultancy, Ltd., the company he founded in 1999 to further his interest in online database
development.
Chris has served as a technical editor on several books from Sams, including PHP and MySQL Web
Development (2004), Sams Teach Yourself PHP, MySQL, and Apache All in One (2004), and Red Hat
Fedora Unleashed (2004). He is the author of Sams Teach Yourself PHP in 10 Minutes (2005) and
SQLite (2004), and co-author of MySQL Phrasebook (2006).
Acknowledgments
I would like to thank the team at Sams Publishing for its ongoing support and guidance while writing
this book. Special thanks to Shelley Johnston, who hired me as a technical editor and then one day
asked if I wanted to write. Indeed I did! After six awesome years working together, Shelley is
moving on, and I wish her every happiness.
You can email or write me directly to let me know what you did or didn't like about this bookas well
as what we can do to make our books stronger.
Please note that I cannot help you with technical problems related to the topic of this book, and that
due to the high volume of mail I receive, I might not be able to reply to every message.
When you write, please be sure to include this book's title and author as well as your name and
phone or email address. I will carefully review your comments and share them with the author and
editors who worked on the book.
E-mail: opensource@samspublishing.com
Mail: Mark Taber
Associate Publisher
Sams Publishing
800 East 96th Street
Indianapolis, IN 46240 USA
Reader Services
Visit our website and register this book at www.samspublishing.com/register for convenient access
to any updates, downloads, or errata that might be available for this book.
Introduction
MySQL is a powerful relational database-management system that supports a richly featured SQL
language. It's fast, easy to use, andbest of allavailable for free!
MySQL is a very popular choice for web development because of its close relationship with PHP.
Many companies provide MySQL as part of a standard web-hosting deal, so you might already have
access to MySQL without needing to install any software.
Sams Teach Yourself MySQL in 10 Minutes is designed to help you get a handle on MySQL quickly
and easily through a series of step-by-step lessons.
You want to learn how to use MySQL for your own applications.
Each lesson is written in simple steps so that you can quickly grasp the overall concept and put it
into practice. The lessons are also designed to stand alone so that you can jump directly to
particular topics as needed.
SQL code is presented using monospace type. Bold text indicates user input.
A database need not be stored on computeralthough, of course, that is what this book is about! A
filing cabinet and a telephone directory both contain databases: They hold information, organized in
a structured manner so that you can easily access the individual item you want to find.
Relational Databases
MySQL is a relational database-management system (RDBMS). The term relational indicates that
MySQL can store its data as a number of different tables that are related to each other in some way.
The advantage of this type of database over a flat table system is that very large databases can be
constructed from different tables, each of which contains only information relevant to that table.
Much has been written about relational database theory, but you need to understand only a little to
create efficient databases. You don't need to be scared by what appears to be a very academic
topica great deal of the principles of relational database design are grounded in common sense. You
will learn more about this in Lesson 16, "Designing Your Database."
One of the primary factors when choosing an RDBMS is cost. MySQL is distributed as open-source
software under the GNU General Public License, so you can actually use MySQL free of charge.
Also available for MySQL is a commercial license that includes various levels of technical support for
users with mission-critical systems. Even with the cost of commercial support, MySQL offers a
significantly lower total cost of ownership over other enterprise-level RDBMS.
MySQL is robust, powerful, and scalable. It can be used in applications from tiny web databases to
very large data warehouses with terabytes of data. You can use MySQL replication or clustering to
guarantee 100% availability. A number of case studies published on MySQL.com give an example of
just what MySQL is capable of.
Case Studies
You can read about how MySQL has been used in large projects at
http://www.mysql.com/why-mysql/case-studies/.
Anatomy of a Database
A database consists of a series of tables. Each table has a name, which is how it is referenced in the
SQL language. Each database also has a name, and the same RDBMS can manage many different
databases. MySQL is a multiuser database and can restrict access to each database to only specific
users.
A database table looks somewhat like a spreadsheet: a set of rows and columns that can contain
data at each intersection. In a relational database, you store different types of data in different
tables. For instance, the sample database in this book has separate tables for customers, products,
and orders.
Each table has a defined set of columns, which determine the values it can store. For example, the
table that contains information about products needs to store a name, price, and weight for every
product. Each row of data can contain values for only the columns defined in the table.
In addition, each column is defined as a particular data type, which determines the kind of values it
can store. The data type might restrict values to numeric or date values, or it might impose a
maximum size.
What Is SQL?
The Structured Query Language (SQL) is the most common way to retrieve and manage database
information. An SQL query consists of a series of keywords that define the data set you want to
fetch from the database. SQL uses descriptive English keywords, so most queries are easy to
understand.
SQL
Sometimes you will hear SQL pronounced as the word sequel, but it's
also okay to pronounce it as the letters S-Q-L.
Virtually every RDBMS on the market uses the SQL language. The MySQL implementation of SQL
conforms to the ANSI SQL standards and implements some of its own extension to handle features
that are specific to MySQL.
About MySQL AB and mysql.com
MySQL AB is the Swedish company that develops, maintains, and markets the MySQL database
server and tools.
MySQL Source
MySQL AB provides technical support to users with commercial support packages. The company also
runs MySQL training courses around the world and issues MySQL Certification to those who want to
become accredited MySQL Developers or Database Administrators.
The MySQL website, http://www.mysql.com/, contains a section called Developer Zone (which you
can access directly at http://dev.MySQL.com/) where you can find online support in the form of
forums, mailing lists, and user groups. Consider joining one of the online communities; they are a
great way to learn more about MySQL from other users.
You can download or view online (in the Developer Zone) a comprehensive reference manual for
MySQL. You can download a printable PDF version or browse an HTML-format manual that is fully
searchable.
Online Manual
Other Resources
A number of MySQL books have been published under the MySQL Press brand. Currently, these
include MySQL Tutorial (2004), MySQL Language Reference (2005), MySQL Administrator's Guide
(2005), and MySQL Certification Study Guide (2004).
Let's take a moment to look at where MySQL will reside on your system. If you do not yet have
MySQL installed, refer to Appendix A, "Installing MySQL."
Linux/UNIX Systems
The location of MySQL programs, libraries, and other files depends on the installation prefix used
when MySQL was installed. Typically, the prefix is either /usr/MySQL or /usr/local/MySQL.
In the location used on your system, you will find the following subdirectories:
bin Contains the MySQL executables, including the database server and all the client programs
lib Contains the development libraries used to communicate with a MySQL database from your
own programs
The MySQL configuration file is named my.cnf. The file /etc/my.cnf contains global settings, but you
can also create a file named my.cnf in the data directory that applies only to that MySQL server; it is
possible to have multiple MySQL servers on one machine.
RPMs
Make sure that the MySQL bin directory is in your system path so you
can avoid having to enter the full path to the client programs when
you want to run them. Refer to your operating system documentation
for details on how to set this up.
Windows Systems
The default install location is C:\Program Files\MySQL. The system is installed in a subfolder that is
named using the MySQL minor version number. For example, MySQL 5.0.18 is installed to
C:\Program Files\MySQL\MySQL Server 5.0.
In the version-specific install location, you will find the following subdirectories:
In the installation directory, you will also find a number of sample configuration files. The current
configuration is found in my.ini located in this folder.
MySQL is installed as a Windows service. To start and stop the database server, go to Control Panel,
Administrativ Tools, and select Services. A program group in the Start menu contains a shortcut to
the MySQL monitor program and the configuration wizard.
Summary
In this lesson, you took your first step with MySQL. You learned a little about what MySQL can do
and how to find support when things go wrong. In the next lesson, you'll learn how to connect to a
MySQL database using the MySQL program.
Lesson 2. Using MySQL
In this lesson, you learn how to connect to a MySQL database and use the mysql command-line
program.
The mysql Client
The mysql program is a command-line client used for sending commands to a MySQL server. It can
be used to enter SQL commands to query a database or alter table definitions; it also has its own
set of commands to control its operation.
$ mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2084 to server version: 4.1.12-standard-log
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql>
The mysql> prompt indicates that you will now be typing commands into the mysql client instead of
the system shell.
When MySQL is first installed, anonymous connections are allowed unless you disable them. It is a
good idea to remove anonymous user access; this is discussed in Appendix A, "Installing MySQL."
If your server does not allow anonymous connections, you will see an error like the following when
you attempt to start the mysql program:
$ mysql
ERROR 1045 (28000): Access denied for user 'chris'@'localhost'
(using password: NO)
If you will be using mysql to connect to a remote database and there is no local MySQL server, or if
the local MySQL server is not running, the error will look like this:
$ mysql
ERROR 2002 (HY000): Can't connect to local MySQL server through
socket '/var/lib/mysql/mysql.sock' (2)
Connecting to MySQL
Even if your database does allow anonymous connections, you will need to connect using a
username and password to do anything useful. To connect to a MySQL database, you must know
the connection parameters to use.
Because MySQL can accept connections over a network, you must specify the database server
hostname. If you are connecting to a MySQL server running on the local machine, the hostname is
localhost. Otherwise, you can use the IP address or hostname of the remote server.
You also need to supply a username and password to authenticate with the database server. As you
will learn in Lesson 18, "Managing User Access," the username and password to access a database
can be locked down so that they work only when you connect from a specific location.
Finally, you must supply the database name to connect to. Each username may have access to one
or more databases on the server; you must authenticate to gain access to your own databases.
The mysql program accepts a number of switches to specify how to connect to a database. Use the
- -user switch to supply a username, and use the - -password switch to supply a password, as
shown:
Note that using this command as shown means that your password is visible onscreen. To avoid
this, use the - -password switch without an argument to be presented with a password entry
prompt.
Enter your password when prompted to log on to the MySQL server. Note that your password is not
displayed onscreen as you type.
Windows Menu
If there is a problem authenticating with the MySQL server using either of these methods, you will
see an error like this:
The value given in - -host can be the IP address of the server or a fully qualified domain name.
Remote Connections
Each of the connection parameter switches to mysql has a shorter version that you can use, if you
prefer. The - -user switch can be replaced by -u, and - -password by - p . When using the shorter
switches, note that the equals sign is not neededthe value is given immediately after the switch.
MySQL Port
The - -database switch can be abbreviated to -D. In fact, the - -database or -D switch can be
omitted, and you can just specify the database at the end of the mysql command, as shown:
Password Argument
When using the short connection switches, make sure that there is no
space between - p and the password. Otherwise, you will be
prompted to enter a password, and the password you gave on the
command line will be treated as the database name.
Executing SQL Statements
Now let's look at how the mysql program is used to execute a SQL statement on a MySQL database.
When you are connected to MySQL, issue the show databases command to see which databases are
available to you. The SHOW DATABASES command is specific to MySQL but is executed through the
mysql program like all other SQL commands.
To select the database named yourdb, use the \u command along with the database name.
mysql> \u yourdb
Database changed
Built-In Commands
Commands that begin with a backslash are internal commands for the
mysql monitor program, not part of the SQL command set.
If you attempt to connect to a database that does not exist, or if you mistype the name, you will see
an error message.
mysql> \u wrongdb
ERROR 1049 (42000): Unknown database 'wrongdb'
You can also specify the database to connect to by using the - -database or -D switch to the mysql
program.
In fact, the mysql program enables you to put a database name after all the switches have been
given without prefixing it with - -database or -D. The following is, therefore, equivalent to the
previous command:
If you are using several databases at the same time, issuing \s is a handy way to find out which one
you are working on at any given time. The following output shows a connection to a MySQL 4.1
server running on a local Windows machine:
mysql> \s
- - - - - - -
C:\Program Files\MySQL\MySQL Server 4.1\bin\mysql.exe
Ver 14.7 Distrib 4.1.14, for Win32 (ia32)
Connection id: 94
Current database: mysqlin10
Current user: root@localhost
SSL: Not in use
Using delimiter: ;
Server version: 4.1.14-nt
Protocol version: 10
Connection: localhost via TCP/IP
Server characterset: latin1
Db characterset: latin1
Client characterset: latin1
Conn. characterset: latin1
TCP port: 3306
Uptime: 35 days 5 hours 34 min 51 sec
Reconnecting
Because SQL commands can span many lines, you must use a semicolon to tell MySQL that a
command is finished.
Look back to the SHOW DATABASES command, in the section "Selecting a Database to Use." You'll see
that it required a semicolon at the end of the command. If this had been omitted, the text on your
screen would look like this instead:
When you press the Enter key and a command has not been terminated, the prompt changes from
mysql> to ->, indicating that you are continuing a command from the previous line of input. You can
enter a semicolon at any time to terminate the statement, and your SQL command can span as
many lines as necessary before being terminated.
Consider the following SQL query (you do not need to understand how it works yet), entered in
mysql. The result of the query from the sample tables used in the book appears directly underneath
the query.
The mysql program enables you to continue entering the query one line at a time; it sends the
query to the MySQL server for execution only when you enter the semicolon to terminate the
statement.
The query results are displayed in tabular format, just as you saw for SHOW DATABASES. The only
difference this time is that there are two columns in the table. This format will quickly become
familiarit is the default output format for all SQL queries executed through mysql.
Underneath the query results is shown the total number of records retrieved by the query and the
total execution time required to produce the results. In this example, the execution time appears to
be zeroin fact, the time taken by the MySQL server was less than one hundredth of a second. Only
when you begin to create complex queries will you notice a significant execution time.
mysql> SELECT *
-> FROM emptytable;
Empty set (0.00 sec)
Instead of the row count, mysql shows the message Empty set. The execution time is still displayed.
However, if you use \G instead of \g, the query results are displayed in a vertical format instead of
the usual tabular layout. This format produces one row of output for each column in the database,
as shown:
mysql> SELECT * FROM products
-> \G
*************************** 1. row ***************************
code: MINI
name: Small product
weight: 1.50
price: 5.99
*************************** 2. row ***************************
code: MIDI
name: Medium product
weight: 4.50
price: 9.99
*************************** 3. row ***************************
code: MAXI
name: Large product
weight: 8.00
price: 15.99
3 rows in set (0.02 sec)
Vertical Format
The vertical query format is very useful when you want to view a
single row of data from a table. The tabular layout might produce
output that is too wide for your screen if the table contains many
columns.
You can also change the default output format to vertical by starting mysql with the - -vertical
switch. Then simply terminating a query with a semicolon will produce output in this format.
Other Formats
Other format options that can be selected with switches when mysql
is invoked are - -html and - -xml. These produce HTML table and
XML data output, respectively.
Use the \e command to open an editor containing the current query. The actual editor used depends
on your system environment; this is usually vi or vim , unless you specify otherwise.
Changing Editors
To change the query editor, set the name of the program you want to
use in the EDITOR environment variable.
After you edit and save the query, you are returned to the mysql client with the prompt showing ->.
It is as if you had just entered the query at the command line. To execute the query again, enter a
semicolon or use the \g or \G commands.
Most modern systems also support command-line editing. You can use the left and right cursor keys
to move along the line currently being entered to change text as you type. You can also use the up
and down keys to cycle through the command history and retrieve commands that you entered
earlier in the session.
Starting Over
If you want to start again with a new SQL statement without running
the command being entered, issue the \c command to clear the
current command and return to the mysql> prompt.
mysql> \T output.txt
Logging to file 'query.txt'
Any queries subsequently executed in mysql will be appended to query.txt and will be displayed
onscreen. The retrieved data and the query itself are both written to the filein fact, the log file
records exactly what is displayed onscreen.
To stop writing to a log file, the \t command cancels any previously issued \T commands.
Exiting the mysql Program
To exit the mysql program, use the \q command. Alternatively, you can type quit or exit to leave
the program.
If you want to run a single host command without exiting mysql, use the \! command. The following
example runs the system command pwd on a UNIX/Linux system to determine the path of the
current working directory:
mysql> \! pwd
/home/chris/public_html
Creating the Sample Tables
Before moving on to the next lesson, you need to create the sample database tables that are used
in this book.
Save this file to your hard disk as sampdb.sql and issue the following command:
The < symbol causes the contents of sampdb.sql to be passed to the mysql program all at once. The
result is that the sample tables are created within the database you specified.
Summary
In this lesson, you learned how to connect to a MySQL database using the mysql program. In the
next lesson, you will learn how to create a simple SQL query to retrieve data from MySQL.
Part 2: Getting Started with SQL
Lesson 3. Retrieving Data
A SELECT statement begins with the SELECT keyword and is used to retrieve information from MySQL
database tables. You must specify the table name to fetch data fromusing the FROM keywordand one
or more columns that you want to retrieve from that table.
A SQL statement begins with a keyword and can contain several more
keywords that must appear in the correct, structured wayknown as
the statement's syntax.
The customers table contains three records. In this statement, we tell MySQL to fetch the value of
the name column; this is displayed for every record in the table.
The data displayed is not ordered. Usually records are retrieved in the same order in which they
were inserted into the database. In this example, the company names are displayed in the order in
which they were inserted in the sample table-creation script.
Order of Records
Although records are normally retrieved in the order in which they are
inserted into the database, you cannot rely on a particular order being
preserved. If your database is backed up and restored, or if a
maintenance operation is performed on the database, MySQL might
alter the order in which records are stored internally.
A SELECT statement will return every row from the table unless you tell it otherwise. You will learn
how to do this, by putting a filter on the query, in the next lesson.
Formatting Queries
The following query retrieves every column and row from the products table:
mysql> SELECT *
-> FROM products;
+------+----------------+--------+-------+
| code | name | weight | price |
+------+----------------+--------+-------+
| MINI | Small product | 1.50 | 5.99 |
| MIDI | Medium product | 4.50 | 9.99 |
| MAXI | Large product | 8.00 | 15.99 |
+------+----------------+--------+-------+
3 rows in set (0.00 sec)
Note that the output produced is exactly the same, as if you had specified each column in the query
by name, like this:
When you use SELECT *, columns are displayed in the order they occur in the database tablethe
order in which columns were specified when the table was created. You will learn how to create
database tables in Lesson 14 "Creating and Modifying Tables."
Compare the order of the columns in the result of the previous query to the output produced by the
DESCRIBE command for products .
The tabular layout that mysql produces when displaying the results of
a query is a simple yet readable format for viewing small amounts of
data. However, your screen has only a fixed width, so if you try to
display too many columnsor if a SELECT * returns a lot of columnsthe
characters that make up this table could wrap lines and create an
unreadable mess.
If you try to select data from a table that does not exist, MySQL gives an error message. In this
example, you attempted to select from a table named product instead of products :
mysql> SELECT *
-> FROM product;
ERROR 1146 (42S02): Table sampdb.product' doesn't exist
If you specify a column name that does not exist in the selected table, you will see the following
error message:
In this case, the customer_contacts table does not have a name columnit has separate first_name
and last_name columns.
Case Sensitivity
MySQL table names are case sensitive, but column names are not. A
table named Products is different than products , and executing
SELECT * FROM Products will produce an error in the sample database.
However, specifying the name column as Name or NAME will not cause an
error.
If you make a syntax errorthat is, when MySQL cannot understand the SELECT statement because
things do not appear in the order that it expects them tothe error message looks like the following:
In the previous example, note the comma after last_name. When MySQL sees this, it expects
another column name to follow, but instead the next word is FROM. Because you cannot use a SQL
keyword as a column name, this causes the syntax error as shown.
MySQL can also throw up a syntax error if you misspell a keyword. In the following example, the
keyword FROM was mistyped as FORM. The error displayed indicates that MySQL does not know what
purpose the word FORM serves in the SQL statement, so it cannot execute this query.
Multiple Errors
If there are several errors in your query, MySQL will tell you only
about the first one that it encounters. Of the three error types shown
previously, MySQL will report a syntax error first, followed by a
nonexistent table and finally a bad column name.
Consider the error in the following statement, in which you mistyped a two-word column name by
leaving out the underscore character in the name. MySQL does not allow column names to contain a
space, so an underscore is often used to separate words.
In this example, MySQL gives an unknown column error instead of a syntax error. The actual way
MySQL interprets this is to select a column named last and give it an alias name, so there's actually
no error in the statement syntax. Don't worry about the details of this for nowit's covered in Lesson
12, "Creating Advanced Joins."
Semantic Errors
If you are connected to one database but want to list the tables in another, you can use a FROM
clause with SHOW TABLES.
Describe
The following query retrieves all the contacts for a given company:
In this example, rows from customer_contacts are returned only if the value of customer_code in that
row is equal to SCICORP.
You often use an exact match operator in a WHERE clause to return all the columns in a table when
you know the primary key of a record. For instance, to find all the information about a product from
its unique product code, you could use the following query:
mysql> SELECT *
-> FROM products
-> WHERE code = 'MIDI';
+------+----------------+--------+-------+
| code | name | weight | price |
+------+----------------+--------+-------+
| MIDI | Medium product | 4.50 | 9.99 |
+------+----------------+--------+-------+
1 row in set (0.00 sec)
To perform a condition using an inequality, use the(=)operator. This works just the same as =, but
the condition returns only rows in which the table value is not equal to the value given in the
condition.
For instance, the following query finds all products except for MINI:
mysql> SELECT *
-> FROM products
-> WHERE code(=)'MINI';
+------+----------------+--------+-------+
| code | name | weight | price |
+------+----------------+--------+-------+
| MIDI | Medium product | 4.50 | 9.99 |
| MAXI | Large product | 8.00 | 15.99 |
+------+----------------+--------+-------+
2 rows in set (0.02 sec)s
When followed by an = symbol, these operators also match equal values. The symbol sequence >=
means "is greater than or equal to," whereas <= means "is less than or equal to."
To find only products for which the price is $9.99 or lower, use the following query:
mysql> SELECT *
-> FROM products
-> WHERE price <= 9.99;
+------+----------------+--------+-------+
| code | name | weight | price |
+------+----------------+--------+-------+
| MINI | Small product | 1.50 | 5.99 |
| MIDI | Medium product | 4.50 | 9.99 |
+------+----------------+--------+-------+
2 rows in set (0.00 sec)
This example uses the <= operator, meaning that rows in which the price value is less than or equal
to 9.99 are returned. If you use the < operator instead, the MIDI product will not be returned by the
query because it costs exactly $9.99.
The range operators can be performed on textual data, and the results are logical. For example,
performing a greater-than comparison on the last_name field returns only values that are
alphabetically higher than the given value.
Word Comparisons
Although the usual convention in a WHERE clause is WHERE column = ' value', this ordering is not
significant. The following query demonstrates that the order can be reversed without affecting the
outcome:
Number Values
Quotes are not needed around number values. MySQL does not get
confused with numeric comparisons because a column name cannot
begin with a number.
MySQL does enable you to perform a query using two columns, although this is rarely useful with
two columns from the same table. A slightly peculiar example is shown here:
This query attempts to find names from the customer_contacts table whose first name and last
name are the same. Such names are unusualthe query will find only names such as Scott Scott or
Thomas Thomasso no rows are returned from the sample tables. Note that this query does not find
matches for Benjamin Franklin and Franklin Rooseveltit compares only the first_name and
last_name values from a single row of data.
mysql> SELECT *
-> FROM products
-> ORDER BY price;
+------+----------------+--------+-------+
| code | name | weight | price |
+------+----------------+--------+-------+
| MINI | Small product | 1.50 | 5.99 |
| MIDI | Medium product | 4.50 | 9.99 |
| MAXI | Large product | 8.00 | 15.99 |
+------+----------------+--------+-------+
3 rows in set (0.00 sec)
Sort Columns
When you want to add sorting to a query that is also filtered, the ORDER BY clause must appear after
the WHERE clause. This example finds all the contacts for one customer sorted on the last name.
The following query fetches data from the orders table in date order. The second sort column,
customer_code , is used to specify the sorting when the values of order_date are the same.
To specify a descending sort direction, use the DESC keyword. The following example sorts the data
from the products table with the heaviest at the top of the list.
mysql> SELECT *
-> FROM products
-> ORDER BY weight DESC;
+------+----------------+--------+-------+
| code | name | weight | price |
+------+----------------+--------+-------+
| MAXI | Large product | 8.00 | 15.99 |
| MIDI | Medium product | 4.50 | 9.99 |
| MINI | Small product | 1.50 | 5.99 |
+------+----------------+--------+-------+
3 rows in set (0.00 sec)
Ascending Order
When you specify more than one sort column, the keywords ASC and
DESC can be used after each column name. You must specify the order
direction for each sort in turn.
Summary
In this lesson, you learned how to filter the rows returned by a SELECT statement using a WHERE
clause. You also learned how to specify a sort order on the result of a query using ORDER BY . In the
next lesson, you will learn how to perform more advanced data filtering on a query.
Lesson 5. Advanced Data Filtering
In this lesson, you learn about more conditional operators that can be used in a WHERE clause. You
also learn how to combine conditions to perform more advanced filtering on a query.
Combining WHERE Clauses
The examples you have seen so far perform filtering on a query based on only a single condition. To
provide greater control over a result set, MySQL enables you to combine a number of conditions in
a WHERE clause. They are joined using the logical operator keywords AND and OR.
This is commonly used to restrict the query results based on the values of two or more columns, as
shown in the following example:
This query returns only rows from the orders table in which both conditions hold true. The
customer_code must be SCICORP, and the order_date must be on or after February 1, 2006.
AND
The following example shows the same example you saw for the AND operator, but using an OR
instead:
The result set for this query includes all orders for SCICORP, regardless of order_date, as well as any
orders for other customers that were placed on or after February 1.
OR
This example finds all the customers who have the name Franklin, whether that is their first name
or last name:
However, because this is a relatively common type of filter, there is a handy shortcut. You can use
the IN operator to perform exactly this type of filter in a single condition. IN works like multiple
equals operators and takes a comma-separated list of values, enclosed in parentheses.
Brackets
You can already see that this query is more concise and easier to read when you use IN.Imagine
how cumbersome a query would become without it if you had to use the OR operator with a long list
of values to compare.
Instead of matching against a list of values, the BETWEEN operator enables you to search for data
within a given range. It takes two target values separated by the keyword AND . Rows in which the
column data is betweenand includingthose values are returned. The following example finds only
orders placedin a given week in January:
mysql> SELECT *
-> FROM orders
-> WHERE order_date Between '2006-01-24' AND '2006-01-30';
+----+---------------+------------+
| id | customer_code | order_date |
+----+---------------+------------+
| 2 | PRESINC | 2006-01-26 |
| 3 | SCICORP | 2006-01-23 |
+----+---------------+------------+
2 rows in set (0.00 sec)
Date Comparisons
Negating a Condition
Using the NOT keyword negates a conditionit makes it behave in the opposite way.
A powerful use of NOT is the NOT IN condition. Instead of specifying a list of values that a column
value should match, you specify a list of values that should be excluded from the query result. The
following query finds customers from a given company code but also excludes a list of names from
the result:
Similarly, you can use the NOT operator with a BETWEEN statement to exclude a range of values from
the query result. The following example finds only orders that were placed outside the period given:
Operator Precedence
Consider the following query, which contains both an AND and an OR operator:
Before looking at the output from this query, try to determine what MySQL is actually looking for
here. This query could filter the customer contact data in two possible ways.
You might expect that the query would return contacts for the company SCICORP with one of the first
names given. Or you might think that it will return anyone named Albert from SCICORP, as well as
any other contact named Benjamin. However, unless you know whether MySQL assigns more
importance to an AND or an OR, you will not be able to say for sure without running the query.
The actual results from the previous query are shown here:
+---------------+------------+-----------+
| customer_code | first_name | last_name |
+---------------+------------+-----------+
| SCICORP | Albert | Einstein |
| SCICORP | Benjamin | Franklin |
| MUSGRP | Benjamin | Britten |
+---------------+------------+-----------+
3 rows in set (0.00 sec)
As you can see, a Benjamin from a company other than SCICORP appears in the results. This is
because MySQL treats an AND with higher precedence than an OR.The effect is that the conditions on
either side of the AND are evaluated first, before the OR operator is considered.
Precedence
To override the natural order of evaluation, you can put parentheses around conditions to indicate
that they should be evaluated together. The following query uses parentheses to override the
operator precedence of the previous example:
Using Parentheses
If you are expecting a query to still return more rows that you want, even with the filtering from a
WHERE clause applied, you can add a LIMIT clause to specify the maximum number of records to be
returned.
By specifying sorting on a query column and using a LIMIT clause to limit the number of rows
returned to just one, you can tell MySQL to return only the record with the highest or lowest value
in that column. The following example returns only the most expensive product from the
productstable, by sorting pricein descending order:
mysql> SELECT *
-> FROM products
-> ORDER BY price DESC
-> LIMIT 1;
+------+---------------+--------+-------+
| code | name | weight | price |
+------+---------------+--------+-------+
| MAXI | Large product | 8.00 | 15.99 |
+------+---------------+--------+-------+
1 row in set (0.00 sec)
Skipping Rows
If the LIMIT clause contains two numbers separated by a comma, the first is an offset argument and
the second is the number of rows to return. The offset specifies the number of rows to skip before
returning thefirst record.
The next two queries show this in action. First select all the customers' email addresses in
alphabetical order and show just the first three rows.
The next query uses an offset value to show the next three rows from the query result.
Not icethat there is no overlap herethe offset value of 3 causes the fourth, fifth, and sixth rows of
the query result to be displayed.
Skipping Rows
Remember that the offset value in a LIMIT clause is the number of rows
to skip, not the number of the first row to display. LIMIT 5 is
equivalent to LIMIT 0,5not LIMIT 1,5.
Summary
In this lesson, you learned how to use AND and OR to add more conditions to a WHERE clause. You also
learned how to restrict the number of rows returned by a query, using LIMIT.
Lesson 6. Numeric Operators and
Functions
In this lesson, you learn about the numeric operators and functions that are available in MySQL,
allowing you to perform operations from basic arithmetic to complex mathematics.
Numeric Operators
In Lesson 4, "Filtering and Sorting Data," you saw how the comparison operators in MySQL were
used to restrict the number of rows returned by a query.
Numeric operators are used in a similar waytwo values appear on either side of a symbol or a
sequence of symbols. This expression equates to a new value in the SQL statement.
You can actually perform a query in MySQL without supplying a table name. This is useful only when
you have an expression as a selected value, but it can be used to show the result of an expression
on fixed values.
Addition in MySQL is performed using the + operator, and subtraction using the - operator. The
following query shows an expression using each of these operators:
A query with no table list returns exactly one row but can contain multiple columns. In this example,
the two columns returned contain the results of the two expressions in the SELECT statement.
The other basic arithmetic operators in MySQL are * and /, for multiplication and division,
respectively. The / operator in MySQL returns a decimal numberit does not truncate the result or
round it to the nearest whole number.
mysql> SELECT 6 * 8, 72 / 9, 2 / 3;
+-------+--------+-------+
| 6 * 8 | 72 / 9 | 2 / 3 |
+-------+--------+-------+
| 48 | 8.00 | 0.67 |
+-------+--------+-------+
1 row in set (0.00 sec)
Precedence
The *, /, DIV , and MOD operators have a higher precedence than + and
-. You can use parentheses where necessary to alter the order in
which an expression is evaluated.
The DIV operator can be used to perform division where only a whole number is returned and any
remainder is simply discarded. The modulo operator is used to find the remainder after division and
is performed using MOD or the % symbol.
Calculated Columns
In the following example, the query retrieves price data from the products table. The third column
contains an expression that applies a fixed discount to the price of each item.
The expression is evaluated for each row in the result set, and the calculated value is returned in its
own column.
Notice that the heading of the calculated column shows the expression in full. If the column value is
calculated as the result of a long expression, this could make the query output much too wide. If
you want to give this column its own name, you can use the AS keyword to specify a column alias.
In the following example, sales tax of 10% is calculated by multiplying the database price by 0.1
using the multiplication operator, *. The calculated column is given an alias tax .
Column Aliases
NULL Values
If a database column does not contain any data, this is represented in MySQL as NULL. A NULL is no
valueit is not the same as zero.
If you perform any kind of arithmetic in which one of the arguments is NULL, the result will also be
NULL, as shown in the following example:
If you want to check for NULL in a query, use IS NULL or IS NOT NULL.
Comparing column = NULL does not work.
Numeric Functions
A function is a MySQL command used in an SQL statement that takes one or more arguments and
returns a value based on the values supplied. Just as with expressions, you can use a function
anywhere a fixed value could otherwise be used, or to manipulate the value returned in a database
column.
Case Sensitivity
Function names are not case sensitive in MySQL. For example, you
can use ROUND(), Round(), or round()these all perform the same
function call.
Arguments
Random Numbers
To generate a random number, use the RAND() function with no arguments. The result is a random
decimal number between 0 and 1.
Shuffling a Query
You can use the RAND() function in an ORDER BY clause to shuffle the
order in which records are returned. Simply use ORDER BY RAND(); the
value of RAND() will be different for each row returned by the query,
and the results will be sorted randomly according to this value.
An optional argument to RAND() specifies the random number seed. This resets the random number
generator to a particular point in its sequence. Whenever the sequence is reset to a known point,
the same sequence of random numbers will be generated.
Random Seeds
You should never need to seed the random number generator with an
argument to RAND(). Calling the function without an argument will
give a number that can be considered random.
Rounding Functions
This set of functions enables you to round decimal numbers in a particular way. Each of these
functions takes a single decimal number argument and returns an integer result.
If you supply a second argument, the number will be rounded to that amount of decimal places
instead of an integer.
The CEILING and FLOOR functions round a decimal number up and down to the nearest integer,
respectively.
Rounding Negatives
The TRUNCATE function takes two arguments, a number and a precision. It does not round the
number, but simply removes from it decimal places in excess of the precision specified.
mysql> SELECT TRUNCATE(12.34567, 3);
+-----------------------+
| TRUNCATE(12.34567, 3) |
+-----------------------+
| 12.345 |
+-----------------------+
1 row in set (0.00 sec)
Mathematical Functions
This set of functions enables you to perform mathematical operations in a query.
To raise a number to a power, use the POW() function. It takes two arguments: POW(a,b) raises a to
the power b.
To find the square root of a number, use SQRT() with a single argument. The following example also
shows how functions can be nested by putting one function call as the argument to another. It
calculates the square root of a number after it has just been squared.
To find the logarithm of a number, use the LOG() function. With one argument, a natural logarithm
(base e) is returned. The opposite of LOG() is EXP()natural log base e is raised to the power given in
the argument.
In the following example, the first column shows the value of e. The second column performs a
natural logarithm on this value.
mysql> SELECT EXP(1), LOG(EXP(1));
+----------------+-------------+
| EXP(1) | LOG(EXP(1)) |
+----------------+-------------+
| 2.718281828459 | 1 |
+----------------+-------------+
1 row in set (0.00 sec)
When called with two arguments, the LOG() function uses the first argument as its base. For
instance, LOG(10,num) returns the logarithm of num to base 10.
Trigonometry Functions
MySQL supports trigonometry functions to calculate the sine, cosine, and tangent of a value using
SIN(), COS(), and TAN(), respectively.
The argument to these functions should be a value in radians. The following examples use PI() to
supply arguments to these functions that are based on [pi].
Inverse Functions
The inverse functions for SIN(), COS(), and TAN() are ASIN(), ACOS(),
and ATAN(), respectively. A valid result will be returned only for
arguments between 1 and +1.
To convert a value in degrees to radians, use DEGREES(). Likewise, to convert radians to degrees,
use RADIANS().
You can actually see these values by executing a condition as a query, as follows:
The output from this query shows each product and its price from the products table. The
conditional column returns TRUE when the price is greater than 10.00.
The first argument is a condition that is evaluated for each row of the query. The value in the
second is returned if the condition is trUE, and the third argument is returned if it is FALSE.
The following example is a very simple shipping rate calculator. If the product weight is less than 5
pounds, shipping costs $1.99; otherwise, it costs $2.99.
The following example uses a CASE statement to determine the shipping rate based on three
different weight bands:
A CASE can contain as many WHEN clauses as you need (in this example, there are two) and an ELSE
clause that specifies a default value. A CASE statement can grow quite large; you must use the END
keyword to indicate that it has ended.
If one of the WHEN clauses contains a condition that is trUE, its corresponding value, given after the
keyword THEN, is returned. Otherwise, the ELSE value is returned.
MySQL examines the WHEN clauses in the order they appear. In this example, the first value returned
from the database is 1.50, which satisfies both WHEN conditions (it is less than both 2 and 5), but
only the value from the first clause is returned.
ELSE
This example reaffirms that NULL and zero are not the same value.
In the previous lesson, you saw how arithmetic and comparison operations were performed on
numeric values. Now you'll see the ways in which you can work with strings in MySQL.
Strings
Comparison Operators
The comparison operators you are already familiar with translate to string values in a logical way.
The equals and not equals operators work almost as you would expect, but MySQL is not case
sensitive when comparing characters.
The following query shows that MySQL produces search results on a string comparison even if the
case of the text does not match:
To force a case-sensitive string comparison, use the BINARY operator to instruct MySQL to compare
the characters in the string using their underlying ASCII values rather than just their letters.
For example, you know that the string abc will match ABC by default, as shown here:
mysql> SELECT ' abc' = 'ABC';
+---------------+
| 'abc' = 'ABC' |
+---------------+
| 1 |
+---------------+
1 row in set (0.00 sec)
However, if you add the BINARY keyword before the expression, the case of each character becomes
important.
BINARY Ordering
The greater than and less than operators perform an alphabetical comparison between two strings.
For instance, cat is a lower value than dog.
The following query selects data from the customer_contacts table based on a range of values using
the BETWEEN operator:
Note that the result from this query does not include records with the first name John. Although the
first letter falls within the specified range, John is considered a greater value than simply the letter J
because it contains more characters.
Compare this to the following query with the range specified using two letters. This time, the John
record is returned because it falls within the range CA to JZ.0
ASCII Comparisons
Wildcards
The LIKE operator works just like the = operator but enables you to specify wildcards in the string to
be matched. An underscore character matches any single character, whereas the percent symbol
matches any number of characters.
For instance, to find all the contacts that have a last name beginning with L, you can use the
following query:
Case Sensitivity
As with other string operators, LIKE is not case sensitive unless you
also use the BINARY operator.
You can use more than one wildcard character in a condition, if desired. The following
example finds only names that contain the r and end with in:
mysql> SELECT last_name
-> FROM customer_contacts
-> WHERE last_name LIKE '%r%in';
+-----------+
| last_name |
+-----------+
| Darwin |
| Franklin |
| Gershwin |
+-----------+
3 rows in set (0.00 sec)
The underscore character matches exactly one character, so using it in a wildcard expression
restricts the values that will be matched using the position of letters within a string instead of simply
the occurrence of a letter.
Changing the previous example as follows returns only names that contain the letter r in the third
position and also end with in. This time, Franklin is excluded from the results.
NOT LIKE Use NOT LIKE with a wildcard pattern to exclude matching
records from the query result.
Type Conversion
The idea of performing arithmetic operations on strings is a peculiar one. Although you will probably
never have cause to do this, it is important to understand how MySQL handles expressions when the
arguments are the wrong data type.
When you try to treat a string as a number, MySQL does its best to convert the value into the
closest numeric equivalent. For example, if you add two numbers that are contained in quotes,
MySQL returns the correct integer result even though these values are strings.
If the string contains text between two numbers, only the first number is used. In the following
example, the string actually contains a numeric expression. Note that this is not evaluated; only the
first number in the stringin this case, 4is taken into account.
MySQL includes many functions that can be used to manipulate strings. You learn the most useful
functions in this section.
String Functions
Refer to the online manual for the full list of string functions:
http://dev.mysql.com/doc/refman/5.0/en/string-functions.html.
Concatenation
Joining two or more strings is known as concatenation. It is performed using the CONCAT() function.
The CONCAT() function can accept more than two arguments and returns a single string made up of
each argument, in turn. Consider the following example:
All the string arguments are concatenated, and the result is as shown. No spaces are included in the
concatenated string unless they are contained in the string arguments themselves.
Often you will want to separate the concatenated values with a character. You can do so using the
CONCAT_WS() function (the WS part stands for "with separator"), taking the separator character as
the first argument.
Compare the output of the following to the previous example, in which CONCAT_WS() is used with a
space character to separate the words in the result.
Concatenation
In print, you cannot actually see that trailing space characters have
been trimmed by RTRIM()you'll just have to trust that they have!
The TRIM() function has a different syntax that enables you to trim other characters than whitespace
from eitheror bothends of a string. The keywords LEADING, trAILING , and BOTH are used to specify
which part of the string to trim, as shown in the following examples:
The opposite of trimming a string is padding it. MySQL provides the LPAD() and RPAD() functions,
which pad a string to a fixed length by inserting characters on the left and right sides, respectively.
The arguments are the string to pad, the required length, and the padding character. The following
example shows RPAD() being used on a database column to pad the name to 10 characters using
periods:
The following query shows some of the email addresses in the customer_contacts table. The second
column shows the character position of the @ sign in each address, and the third column shows the
total length of the string.
The REPLACE() function can be used to replace one substring with another within a string. In the
following example, the @ sign in an email address is replaced by the word at.
Breaking Up a String
To return only a fixed portion of a string, use SUBSTRING(). The arguments are a string, a character
position, and a length. The portion of the string beginning at the position is returned, up to the
maximum length given.
The following query returns product names from the database, up to a maximum of 10 characters:
Substring Shortcuts
If you omit the length argument, the substring returned is taken from
the given start position to the end of the string.
SUBSTRING() is useful when you want to split a string based on fixed character positions. To split a
string based on the actual character values within it, MySQL provides the SUBSTRING_INDEX()
function, so you don't have to use a clumsy combination of SUBSTRING() and LOCATE() .
SUBSTRING_INDEX() takes a string argument followed by a delimiter character and the number of
parts to return. After you break up the string using the delimiter, that number of parts is returned
as a single string.
The following example returns the suffix from an Internet domain name:
In the previous example, if you were sure that domain suffixes are
always three characters long, you could use SUBSTRING() with a -3
start position.
However, because the suffix might be .com , .name, .ca, and so on, the
period delimiter must be used instead of a fixed character position.
Case Conversion
To convert a string to all lower or upper case, use LOWER() and UPPER(). The following example
shows the same column value converted to both cases:
No single function exists in MySQL to capitalize only the first letter of a string, as you might often
want to do with a person's name. The following shows how you can nest functions, combining
LOWER() and UPPER() with SUBSTRING() and CONCAT() to produce this result:
In the previous lesson, you learned that a NULL is no value and that it is not the same as the
number zero. Using NULL in an expression always causes the result to be NULL.
Similar rules apply for strings: NULL is not equal to an empty string. The following example also
shows that having a NULL argument to CONCAT() causes NULL to be returned, regardless of the other
arguments:
You can have both date and time components in a single value,
represented in the format YYYY-MM-DD HH:MM:SS.
This format places the most significant value first and the least significant last. Consequently,
comparisons between dates take place in a logical way. In the following example, MySQL is simply
comparing two strings or two numbers:
However, using the addition and subtraction operators on a date represented in a string can cause
unpredictable results. Remember from the previous lesson that MySQL tries to perform numeric
operations on a string by taking only the first numbers that appear.
Even using the numeric format with no hyphens, the results are far from perfect. In the following
example, adding 7 days to March 30 should return April 6. Instead, the result looks like an invalid
date in March.
In the sample database, the order_date column in the orders table is a date type column. The
following example shows that arithmetic on those date values can still produce dates that do not
exist.
Date Columns
Date Arithmetic
To instruct MySQL to perform date arithmetic using the addition and subtraction operators, you
must use the INTERVAL keyword along with a unit of time.
The following example adds 7 days to December 30, 2005, using date arithmetic:
As you can see in this example, the value returned is the correct date after adding 7 days to
December 29, 2005the year, month, and date values have all been affected.
Changing the INTERVAL value provides an easy way to add different units of time to a date value. For
instance, without needing to know how many days are in a given month, you can add 1 month to
the date as follows:
Time intervals can also be used. The following example shows that when the time is incremented
past midnight, the day value is also incremented:
Intervals
In these examples, the intervals used were 7 DAY and 2 HOUR rather
than 7 DAYS and 2 HOURS. MySQL requires the unit keyword to be
singular, regardless of English grammar rules.
Table 8.1 lists the unit values that can be used with the INTERVAL keyword.
Table 8.1.
INTERVAL Unit
Keywords
for Date
Arithmetic
Keyword
MICROSECOND
SECOND
MINUTE
HOUR
DAY
WEEK
MONTH
QUARTER
YEAR
There are a number of compound INTERVAL unit keywords, made up of two of the keywords from
Table 8.1 separated by an underscore. The following example adds 2 hours and 30 minutes to a
date using the HOUR_MINUTE unit:
Note that when using a compound unit, the two unit values must be enclosed in single quotes and
separated using a space character.
Date Functions
MySQL includes a range of functions for manipulating date and time values. You learn the most
useful functions in this section.
Date Functions
Refer to the online manual for the full list of date and time functions:
http://dev.mysql.com/doc/refman/5.0/en/date-and-time-
functions.html.
The NOW() function returns the current date and time as a single value.
Time Zones
The time zone upon which all others are calculated is Coordinated Universal Time, abbreviated to
UTC. The time in Hawaii is 10 hours behind UTC, written as UTC-10, whereas in Japan, the local
time is UTC+9. Daylight saving time can modify this further at certain times of the year.
To return the current date and time using a UTC clock, use UTC_DATE() and UTC_TIME(). To return a
single date and time value, use UTC_TIMESTAMP(). The output in the following example is from a
MySQL server based on the West Coast of the United States, which is UTC-8:
You can use the CONVERT_TZ() function to convert a time from one time zone to another. Given a
date value and two time zone names, CONVERT_TZ() returns the date converted from the first time
zone to the second.
In the following example, the date is converted from Pacific Standard Time to Eastern Standard
Time:
Not all systems support all time zone names. If the previous example
does not work, MySQL might not be configured with time zone
support. Contact your system administrator or refer to
http://dev.mysql.com/doc/refman/5.0/en/time-zone-support.html.
Formatting a Date
To display a date in a different format, use the DATE_FORMAT() function. The first argument is a date;
the second argument is a format string, specified using a series of characters prefixed with a %
sign. Other characters in the format string are included in the result verbatim.
The following example formats a date using the full textual day and month names, and an ordinal
suffix on the date:
Table 8.2 shows the full list of format characters for a date.
Character Meaning
%a Abbreviated weekday name (SunSat)
%b Abbreviated month name (JanDec)
%c Month number, no leading zero (112)
%D Day of the month with ordinal suffix (1st31st)
%d Day of the month (131)
%j Day of the year, three digits (001366)
Character Meaning
%M Month name (JanuaryDecember)
%m Month number, two digits (0112)
%U Week number using Sunday as first day of
week (0153)
%u Week number using Monday as first day of
week (0153)
%W Weekday name (SundaySaturday)
%Y Year, four digits
%y Year, two digits
To format a date, you can still use DATE_FORMAT() with a different set of format codes. The following
example shows just one way to format the current time returned by NOW():
Table 8.3 lists all the format characters that can be used to format a time.
Character Meaning
%H Hour on 24-hour clock, two digits (0023)
%h Hour on 12-hour clock (0112)
%i Minutes, two digits (0159)
%l Hour on 12-hour clock, no leading zero (112)
%p A.M. or P.M.
%r Time on 12-hour clock as HH:MM:SS
Character Meaning
%s Seconds, two digits (0059)
%T Time on 24-hour clock as HH:MM:SS
Percent
The syntax of EXtrACT() uses the same interval specifier as date arithmetic, with the keyword FROM.
The following example returns the day number part of the current date:
If you use a compound unit, the values are returned as a single number with the most significant
value first. The following example returns the year and month from the current date:
Date Arithmetic
To compute the difference between two dates, use the DATEDIFF() function. Given two date
arguments, DATEDIFF() returns the number of days between the second date and the first.
If the second date is greater than the first, the value returned is negative, as shown in this
example:
Time Components
You can use TIMEDIFF() to calculate the difference between two times. The result returned is a time
value, as shown in the following example:
The UNIX_TIMESTAMP() function returns the time stamp value of a date. If it is called with no
arguments, it returns the current time stamp.
The following example counts the total number of orders that have been placed in the sample
database:
NULL Values
To find the number of unique values in a column, use COUNT() with the DISTINCT keyword. The
following example finds the total number of customer contacts in the database and also the number
of unique last names:
If you include an expression within SUM(), it is evaluated for each row of data and the total result is
returned, as shown in the following query:
You can use SUM() with a conditional expression to return the number of rows that meet the
condition. Because the expression evaluates to 1 each time the condition is true and 0 each time it
is false, the following query finds the number of products that weigh less than 5 pounds:
The AVG() function computes a mean average. The same result could be performed using SUM() and
COUNT(), as follows:
NULL Values
The next query finds the date of the most recent order placed by using MAX() on the date_ordered
column of the orders table.
Grouping is a SQL feature that enables you to produce summary data on groups of rows in the
result set.
Consider the first example in this lesson, in which you performed a query using COUNT(*) to find the
total number of orders in the database. Suppose that now you want to know the total number of
orders for each customer.
By adding a WHERE clause, you could restrict the count using a customer_code value, but you would
have to perform this query once for each customer to find all the totals. By grouping data instead,
you can perform the aggregate function for each customer in a single query.
The GROUP BY clause collates rows in which the column specified contains the same value so that
many table rows are returned as a single row of data. With data grouped in this way, you can add
an aggregate function to the SELECT statement, and that function will be evaluated for each table
row that was included in the group.
The following query finds the total number of orders for each customer in the database:
The following example selects the number of orders in the database grouped by month, using the
DATE_FORMAT() function to return only the month and year from the order_date column:
Although you could specify the full column calculation in the GROUP BY clause, it's clearly more
convenient to use a table alias here.
Note that the ORDER BY clause in this query uses order_date, not order_monthyou want the results to
be shown in date order, not alphabetically, which would show February before January.
ordering
The following example groups data from the orders table by both month and customer. The
summary data produced shows a breakdown of the number of orders placed by each customer in
each month.
The order in which the columns are given in the GROUP BY clause does not affect the grouping. The
following example reversed the column order so that customers appear first, followed by a
breakdown of their orders by month. Although it would make for more readable code to specify the
grouped columns in the same order they are selected, this example shows that it does not actually
affect the query results:
In lesson 4, "Filtering and Sorting Data," you learned how to filter data using a WHERE clause and a
condition that references a table column. You cannot reference a column produced by an aggregate
function in a WHERE clause. Instead, you must use HAVING.
The following query finds dates on which more than one order was placed. It groups data from the
orders table by order_date and uses a HAVING clause on the COUNT(*) aggregate to find where that
group is made up of more than one table row.
Similarly, the next example looks at the order_items table and finds which products have shipped at
least 30 units. In this example, a column alias is used on the summary column and also in the
HAVING clause.
Filtering by Subquery
You can use the result of a query like you use a list of values with the IN operator to filter a query
based on the result of another query. The subquery appears in parentheses after the IN keyword.
The following query fetches all columns from the products table, but only for those product codes
that were part of order number 1:
mysql> SELECT *
-> FROM products
-> WHERE product_code IN (
-> SELECT product_code
-> FROM order_lines
-> WHERE order_id = 1
-> );
+--------------+---------------+--------+--------+
| product_code | name | weight | price |
+--------------+---------------+--------+--------+
| MINI | Small product | 1.50 | 5.99 |
| MAXI | Large product | 8.00 | 15.99 |
+--------------+---------------+--------+--------+
2 rows in set (0.00 sec)
Formatting Subqueries
In the previous example, the subquery was indented from the main
query for clarity. Remember, you can use as many spaces and
carriage returns as you like to keep things readable.
Let's break down how MySQL evaluates this query. First, the subquery is executed to find a list of
product codes. If you run the subquery on its own, you will see the following result:
mysql> SELECT product_code
-> FROM order_lines
-> WHERE order_id = 1;
+--------------+
| product_code |
+--------------+
| MINI |
| MAXI |
+--------------+
2 rows in set (0.00 sec)
So using this result, after evaluating the subquery, MySQL runs a query that is the same as the
following:
mysql> SELECT *
-> FROM products
-> WHERE product_code IN ('MINI", 'MAXI")
+--------------+---------------+--------+-------+
| product_code | name | weight | price |
+------------- +---------------+--------+-------+
| MINI | Small product | 1.50 | 5.99 |
| MAXI | Large product | 8.00 | 15.99 |
+--------------+---------------+--------+-------+
2 rows in set (0.01 sec)
As you can see, using a subquery in this type of situation saves you from having to perform two
queries separately and insert the result of the first into the secondeither yourself by hand or using a
data structure in a programming language.
Query Performance
MySQL cannot evaluate this type of subquery by feeding the result of the inner SELECT statement
into the outer query because each SELECT statement relies on values from the other.
To reference the same table more than once in the same query, you must use table aliases. These
work just the same as the column aliases you have already come across, but they enable you to
qualify columns from a table using an abbreviated alias.
To alias a table, give it an alias name immediately after the table name in the FROM clause. The AS
keyword is optional for table aliases.
The following example uses a correlated subquery on the order_lines table, comparing the average
quantity of each product ordered at a time to every order that included that product in turn. The
result is a list of orders in which a higher than average quantity of each product was shipped.
The query fetches data from the order_lines table twice, aliased to ol1 and ol2 . The
tablename.column notation is used to qualify a column name in SQL; in this case, however, the table
name would be the same, so two different aliases are required.
This example is a correlated subquery because the inner subquery cannot be executed outside this
complete SQL statement. It references ol1 .product_code, a column from the outer query.
Correlated Subquery Performance
Note that this is not a correlated subquery. The subquery can be evaluated independently of the
outer query and the result used as the argument to the = operator. The result is all the contacts
who are related to the same customer record as the given contact name.
Using the equals operator with a subquery means you must be sure that the subquery returns only
one row; otherwise, you must use IN. With the sample database, you know there is only one
Benjamin Franklin, so there is no problem. However, be aware that MySQL generates an error as
shown here if the subquery returns more than one row for an equals operator:
The following example retrieves each product from the database along with a subquery column that
finds the total quantity ordered for each product in turn:
Table Joins
This subquery example involves a type of table join in which the filter
on the query involves a column value from another table. Joins are
covered in more detail in the next lesson.
This feature will become more useful when you have learned how to perform advanced table joins in
the next few chapters. For now, you'll see how it works with a trivial example.
The following query uses a subquery in place of a table in the FROM clause. The subquery returns a
subset of the data from the customer_contacts table.
Performing a SELECT * on that virtual table can return only the columns included in the subquery.
The WHERE clause in the main query takes effect after the data has already been filtered in the
subquery.
mysql> SELECT *
-> FROM (
-> SELECT first_name, last_name
-> FROM customer_contacts
-> WHERE customer_code = 'SCICORP'
-> ) scicorp_customers
-> WHERE first_name = 'Benjamin';
+------------+-----------+
| first_name | last_name |
+------------+-----------+
| Benjamin | Franklin |
+------------+-----------+
1 row in set (0.00 sec)
When using a subquery as a table, you must give the subquery a table alias or MySQL will return an
error. In the previous example, the virtual table was aliased to scicorp_customers.
Summary
In this lesson, you learned about the ways in which subqueries can be used in MySQL. In the next
lesson, you will learn how tables in a relational database are joined in a SQL query.
Lesson 11. Joining Tables
In this lesson, you learn what joins are and how they are used in SELECT statements to retrieve data
from different tables.
Understanding Joins
The capability to join tables is probably the most important feature of MySQL, so it is important that
you understand how to construct a SELECT statement that includes a join.
A relationship exists between the customers and customer_contacts tables. There might be more
than one contact person for each customer, assuming that a customer is a company and that you
can deal with people in different departments. By splitting this information into two tables, you
avoid duplicating data that is always the same for contacts within the same company.
Duplicate Data
To keep the examples in this book simple, the sample tables contain a much smaller amount of
information than you would find in a real-world database. Still, the concept is the same. The sample
table customers contains a name field, which is the name of the customer. In a live database, this
table would also contain a corporate address and any other information that is the same for a
customerand is the same for all the contact persons for that customer.
The customer_contacts table is used to store multiple contacts for a customer. The customer_code
field in this table acts as a link back to the customer data. The value of contacts.customer_code
corresponds to the customers.customer_code value and is the key field used when joining these
tables.
Keys
The following query joins the customers and customer_contacts tables to produce the complete
contact information from the sample database. Because this query retrieves the entire contacts
database, there is only one WHERE condition; this tells MySQL that the relationship between the
tables is that the customer_code value is a reference to the customer_code column in customers.
Cartesian Products
The condition in the WHERE clause that indicates the relationship between joined tables is very
important. To see why, look at what happens when you specify two tables in the FROM clause without
any conditions.
Two small tables are included in the sample database, named t1 and t2. These tables contain just a
few rows to demonstrate joins. First, familiarize yourself with their data:
mysql> SELECT *
-> FROM t1, t2;
+----+--------+----+--------+
| id | letter | id | letter |
+----+---- ---+----+--------+
| 1 | A | 1 | X |
| 2 | B | 1 | X |
| 3 | C | 1 | X |
| 1 | A | 2 | Y |
| 2 | B | 2 | Y |
| 3 | C | 2 | Y |
| 1 | A | 3 | Z |
| 2 | B | 3 | Z |
| 3 | C | 3 | Z |
+----+--------+----+--------+
9 rows in set (0.00 sec)
As you can see, each row from t1 is combined with each row from t2. Three rows in each table
produce a join, resulting in a total of nine pairs of records. This is known as a Cartesian product,
and it is rarely the result you would want from a query.
SELECT *
The total number of rows returned is the product of the number of rows in each table. You can
imagine how large the resulting data set can grow when the individual tables contain a large
number of rows themselves.
Cross Joins
Adding a WHERE condition to this join instructs MySQL to filter out the pairs of records for which there
is no relationship between the data. This is the majority of the rows that would be returned in a
Cartesian product. Assuming a relationship between the id column in each table, the join then
produces the following result:
mysql> SELECT *
-> FROM t1, t2
-> WHERE t1.id = t2.id;
+----+--------+----+--------+
| id | letter | id | letter |
+----+--------+----+--------+
| 1 | A | 1 | X |
| 2 | B | 2 | Y |
| 3 | C | 3 | Z |
+----+--------+----+--------+
3 rows in set (0.00 sec)
Take a moment to look back at the result of the Cartesian product, and you will see that the three
rows returned by the previous example appear, but the other rows have been discarded.
Join Types
Foreign Keys
Even if your table definition has a foreign key defined (you will learn
how to do this in Lesson 17), you must include a WHERE clause that
specifies the join condition. The relationship to be used for a join is
never stored at the database level.
To perform an equijoin on multiple tables, a condition in the WHERE clause must specify a relationship
from every table to another table. In this example, there are relationships between orders and
order_lines, and between order_lines and products .
Each row in order_lines adds the specified quantity of a product to an order. The order_id column
in order_lines joins that table to orders, and the product_code column joins it to products. The first
two conditions in the WHERE clause indicate these relationships. The third filter is used to return only
the order history for SCICORP.
Joining Tables
In the previous lesson, you learned how to join two or more database tables by specifying a list of
table names in the FROM clause of the SQL statement.
MySQL provides an alternate syntax using the JOIN keyword that allows several different types of
table joins to be performed.
Inner Joins
An inner join, or equijoin, is a join that uses a condition to specify a relationship between tables in
which a column in one table is equal to another column in the other table. In the previous lesson,
you learned how to do this using the WHERE clause.
The alternative syntax uses the keyword phrase INNER JOIN to specify a table to join to and the
keyword ON to specify a conditional clause that indicates the relationship between the tables.
The following example reproduces the query from Lesson 11, "Joining Tables," to retrieve all the
customer contact information:
The keywords INNER JOIN appear immediately after the FROM clause and before any filtering is
specified. When you use JOIN, the relationship between tables is defined after using the ON keyword
instead of WHERE. This syntax for a join is longer, but often it is more readable because the WHERE
clause is used only to filter the resulting data set.
Check back to the corresponding example in the previous lesson, and you will see that its WHERE
clause is identical to the ON clause given previously.
Using JOIN
Whether you put multiple tables in the FROM clause and specify the
join condition in the WHERE clause, or use JOIN ... ON is a matter of
preference. Use whichever format you feel most comfortable with.
Joining Multiple Tables
To join multiple tables using the JOIN ... ON syntax, each table has its own JOIN keyword and its
own ON clause immediately afterward.
The following example reproduces the query from Lesson 11 that retrieves the order history for a
given customer, joining the orders,order_lines, and products tables:
In this example, the orders table appears in the FROM clause, and order_lines and products are each
given after an INNER JOIN keyword. This is the logical order in which to write the query because it
has a hierarchical structureorders contain order lines, which, in turn, reference products. The orders
table is referenced in the WHERE clause.
However, when using INNER JOIN, the tables can be specified in any order without affecting the
outcome of the query.
Inner Joins
The majority of joins you will want to perform are inner joins, so this
is the default behavior for the JOIN keyword. You can use JOIN on its
own instead of INNER JOIN, and your query will work the same way.
The ON Clause
The ON clause works just like a WHERE clause but is specific to a join
condition. If you need to, you can add extra conditions to the ON
clause using AND , just as you can with WHERE.
Cross Joins
You saw in the previous lesson that if no relationship between joined tables is given in the WHERE
clause, a Cartesian product or cross join is produced.
The ON keyword is not required to appear after the JOIN keyword, so the same result can be
obtained using INNER JOIN and no ON clause.
However, for readability, you can use the CROSS JOIN keyword to show in your query that the
Cartesian product is the desired result. The following example reproduces the cross join between
sample tables t1 and t2 from the previous lesson:
mysql> SELECT *
-> FROM t1
-> CROSS JOIN t2;
+----+--------+----+--------+
| id | letter | id | letter |
+----+--------+----+--------+
| 1 | A | 1 | X |
| 2 | B | 1 | X |
| 3 | C | 1 | X |
| 1 | A | 2 | Y |
| 2 | B | 2 | Y |
| 3 | C | 2 | Y |
| 1 | A | 3 | Z |
| 2 | B | 3 | Z |
| 3 | C | 3 | Z |
+----+--------+----+--------+
9 rows in set (0.01 sec)
You will use a cross join very rarely, so it is helpful to use this syntax to make it clear that you
actually want to perform this type of join.
Self-Joins
Sometimes you want to join a table to itself. You can do this either by putting the same table name
in the FROM clause twice or by using that table after a JOIN keyword.
The following example uses a self-join to find people in the customer_contacts table who belong to
the same company as a named person. You achieved the same result in Lesson 10, "Using
Subqueries," using a subquerythis is a different approach to the same problem.
In this example, the customer_contacts table is used twice, as an alias to c1 and c2. By joining the
table to itself in the customer_code field, the result is a data set that includes a pair of records for
every person alongside every other person in the company. The filter in the WHERE clause restricts
the output of the query to only find those contacts who share a company with Charles Darwin.
Of course, if you already knew the customer code that corresponded to the person you were
searching for, the query would need to look at customer_contacts only once and filter using the
appropriate condition on customer_code . The self-join is necessary only because the known valuea
contact person's namecannot be used to perform the required filter directly.
Aliases with Self-Joins
When you join a table to itself, it is vital that you give each table an
alias. The tables will, of course, contain exactly the same columns, so
you must use aliases to qualify the columns you want to reference.
Note that the columns selected in the previous example are from the table aliased to c2, not c1. The
filter is performed on values in c1 and restricts the records returned to a particular name. Therefore,
if you had selected the name values from c1, they would all be the same.
You have now seen two different ways to find the same information:
using a self-join and a subquery. The "best" method often depends on
the nature of the tables and the data involved.
In the very small sample database, you will not notice any difference
in performance between the two methods. In a real-world system,
however, if you find that one method is particularly slow, see if
another approach to your query speeds things up.
Natural Joins
The keyword phrase NATURAL JOIN performs a join on two tables without needing an ON or WHERE
clause to specify the relationship between the tables. Instead, MySQL assumes that the tables are
related by all the columns that have the same name in both tables.
Whether you can use NATURAL JOIN depends on the column-naming convention used. For instance,
in the sample database are columns named product_code in both the products and order_lines
tables. The relationship between these tables is suitable for a NATURAL JOIN, as shown in the
following example:
If the relationship between two tables relies upon a join that references columns that do not have
the exact same name in both tables, you cannot use a NATURAL JOIN.
Outer Joins
Most joins return rows based on pairs of records from the two joined tables according to a given
relationship. The outer join is different: All the rows from one table are returned, regardless of
whether the relationship condition finds a matching row in the second table. When no corresponding
record is found, columns that would otherwise contain values from the second table contain NULL.
Outer joins are useful in producing reports when you do not want to exclude a record from the
result if it does not have any corresponding data in a joined table.
The following example uses an outer join to produce a report of the customer orders placed in the
month of February only:
Because Presidents Incorporated placed no orders in the date range specifiedyou will see in the
orders table that orders were placed only in Januarythe order date returned is NULL.
LEFT JOIN
The join keyword used in the previous example was LEFT OUTER JOIN,
which is often shortened to LEFT JOIN. The LEFT keyword tells MySQL
that the left tablethe one specified first, in the FROM clauseshould
return every row with NULL in the right table when no match is found.
You can use RIGHT OUTER JOIN or RIGHT JOIN to reverse the behavior
so that the table given after JOIN must return every row.
Exactly one row is returned for a customer record when there is no corresponding order data,
whereas the other customers have multiple rows returned according to their actual order history.
Notice that the filter on order_date is given in the ON clause, not the WHERE clause. Because the
query returns a NULL order_date value for rows in customers that do have any orders, putting this
filter in the WHERE clause would prevent those NULL values from being returned.
Summary
In this lesson, you learned how to perform inner joins, cross joins, natural joins, self-joins, and
outer joins. In the next lesson, you will learn how to combine the result of two or more queries
using set operations.
Lesson 13. Combining Queries
In this lesson, you learn how to combine the results from different queries using the UNION operator.
Understanding Combined Queries
Mosy SQL queries contain just one SELECT statement that can return data from one table, or several
tables using a join. The technique of combining two or more independent queries into a single data
set is usually known as a union or a compound query.
You might want to use this technique to retrieve records from two tables that have a similar
structure in a single query. For instance, suppose you have archived off some data so that you have
a customers table that contains your current customers and another table called old_customers .
These tables would have the same structureor at least would share many common columns if new
columns had been added to the customers table since the archive took place. Therefore, you could
perform a query on this table that takes into account both current and archived customers. This
would look something like the following:
You can also use UNION to perform two different queries on the same table and combine the two
results into a single data set.
The following simple example demonstrates how the UNION operator works by combining two
separate queries on the customer_contacts table:
All the rows from the first query are returned first, followed by all the rows from the second query.
Terminating Queries
As you might have noticed, the previous example produced the same result that you can achieve
using a single SELECT and an IN operator in the WHERE clause to select multiple values for
customer_code .
The following example produces a result that cannot be accomplished any other way. Two different
columns from the same table are selected in two different queries and combined using the UNION
operator.
The output is abbreviated to save space, but the full output contains every first_name and
last_name value from the customer_contacts table, returned in a single column.
However, although the customer_contacts table contains 11 total rows, 3 of the values were
duplicated; by default, the UNION operator returns only unique values. The duplicate names in this
UNION are Benjamin (which appears as a first_name twice), Roosevelt (which appears as a
last_name twice), and Franklin (which appears once as a first_name and once as a last_name).
If you want to ensure that every value in a UNION is returned, use the UNION ALL operator. This
example would then look like the following:
Sorting a UNION
Notice that in the previous example, the column heading is first_name, even though half the values
returned were fetched from the last_name column. The column headings on UNION are taken from
the column names or aliases in the first query only.
Therefore, to specify a sort order on a UNION, you must use the column name from the first query in
the ORDER BY clause. The following is an example:
It is important to realize that even though the ORDER BY clause appears to relate to the last query in
the UNION, it actually applies to the entire result set. The individual SELECT statements are executed,
then combined, and finally sorted using the ORDER BY rule.
Ordering
MySQL does not understand these keywords, but there are ways to perform these operations using
other techniques.
Performing a MINUS
The MINUS operator usually is placed between two queries. The result of the first query is returned,
excluding any identical rows that are produced by the second query.
Using a similar example to the others in this chapter, you could use MINUS to find only first_name
values from customer_contacts that are not also used as last_name values. The following query
would return all the first_name values except for Franklin:
SELECT first_name
FROM customer_contacts
MINUS
SELECT last_name
FROM customer_contacts;
To reproduce this functionality in MySQL, you can rewrite the query as a subselect using the NOT IN
operator, as follows:
SELECT first_name
FROM customer_contacts
WHERE first_name NOT IN (
SELECT last_name
FROM customer_contacts
);
An alternative, although not as readable, way to execute the same query uses a LEFT JOIN, as
follows:
SELECT c1.first_name
FROM customer_contacts c1
LEFT JOIN customer_contacts c2
ON c1.first_name = c2.last_name
WHERE c2.last_name IS NULL;
Using a LEFT JOIN causes every row from c1 to be returned even if there is no matching row in c2.
When there is no matching row, the values returned for c2 are all NULL. By filtering on the NULL
values, you can exclude values for which the join was successful.
Optimizing MINUS
Both the techniques discussed in this section can produce very slow
queries: The NOT IN operator cannot use an index, and a LEFT JOIN
often has to process very large amounts of data in memory. If neither
performs well enough for your situation, consider using a temporary
table instead, as discussed later in this lesson.
Performing an INTERSECT
The INTERSECT operator usually is placed between two queries; any data row that appears in the
result of each individual query will appear in the overall result.
Using a similar example to the others in this chapter, you could use an INTERSECT to find only
first_name values from customer_contacts that are also used as last_name values. The following
query would find only the name Franklin from the sample tables:
SELECT first_name
FROM customer_contacts
INTERSECT
SELECT last_name
FROM customer_contacts;
An INTERSECT can be performed as a join in which you compare values from two different tables that
are not otherwise related. For example, you could rewrite this query as follows:
SELECT c1.first_name
FROM customer_contacts c1
JOIN customer_contacts c2
ON c1.first_name = c2.last_name;
No relationship exists between first_name and last_name, but you can use these values as the join
condition to simulate an INTERSECT.
Using Temporary Tables
Temporary tables in MySQL can be a powerful means of manipulating a data set. A temporary table
exists only for the duration of your MySQL session, after which it is automatically deleted.
Otherwise, it works just the same as a regular database table.
You will learn more about creating database tables in Lesson 14, "Creating and Modifying Tables."
For now, consider some examples to simulate different types of a compound query.
Performing a UNION
To join two or more queries using a temporary table, you need to insert the data rows from both
queries into the same table.
First, create a new table using the first query to define the columns. The result of this query will also
be inserted into the table.
In this case, a temporary table with a single column is created. You can then insert the result of the
second query as follows:
The table myunion now contains the union. In fact, if you performed a SELECT on this table, it would
give the same result that a UNION ALL operation on the two queries would produce. To simulate a
UNION, in which only distinct values are returned, execute this command:
Performing a MINUS
To simulate a MINUS using a temporary table, first create a new table using the first query to define
the columns and populate the initial data rows.
Then delete the rows that also appear in the second query using a subquery, as follows:
The data remaining in the myminus table is the same result that you would have achieved using a
MINUS operator on the two queries.
Performing an INTERSECT
To simulate an INTERSECT using a temporary table, first create a new table using the first query to
define the columns and populate the initial data rows.
Then delete the rows that do not also appear in the second query using a subquery and the NOT IN
operator, as follows:
The data remaining in the myminus table is the same result that you would have achieved using an
INTERSECT operator on the two queries.
Summary
In this lesson, you learned how to combine the results from different queries using the UNION
operator, and how to simulate the MINUS and INTERSECT operations in MySQL. In the next lesson,
you will learn how to manage database tables.
Part 4: Creating a New Database
Lesson 14. Creating and Modifying Tables
In this lesson, you learn how to use the SQL commands for managing tables and databases in
MySQL. This subset of SQL is known as the Data Definition Language.
Before we look at how tables are managed in MySQL, we should examine the command set that is
used to create databases on a MySQL server.
Creating a New Database
You use the CREATE DATABASE command to create a new database. To create a new database named
newdb, issue the following command. The output will be as shown if the database is created
successfully.
Creating Database
Usually you execute this command when you are connected as the
root user, but you can create databases when logged in as any user
who has the CREATE privilege. You will learn more about the privilege
system in MySQL in Lesson 18, "Managing User Access."
The database name can be up to 64 characters in length and can contain any character that is
allowed in a directory name on your underlying operating system, except for the / and \ characters.
The database name also cannot be one of the SQL reserved words listed in Appendix F, "MySQL
Reserved Words," which can be found on the book's website at www.samspublishing.com.
The database name must be unique as well. If you attempt to issue a CREATE DATABASE statement
for a database that already exists, you will see an error. The following output is produced when you
attempt to create newdb for a second time:
The optional attribute IF NOT EXISTS can be added to a CREATE DATABASE statement to avoid an error
if the database already exists. Instead, a warning is generated, which you can view using the SHOW
WARNINGS command.
Because a warning is generated instead of an error, you can use this technique in a batch script that
contains a series of SQL commands to set up a database; the script will continue on to the next
command if the database already exists.
Character Sets and Collations
MySQL supports different character sets and collations to provide functionality for users who want to
create database applications in different languages.
The character set determines how MySQL stores character data. Each letter in a character string is
represented internally by a numeric value, and the character set determines the character mapping
of each number.
A collation is a set of rules for comparing characters in a character setessentially, it defines the
alphabetical order for a character set. For instance, the character Ö in a German character set is
usually treated as OE for ordering purposes.
Collation rules can also take into account case sensitivity. You saw in Lesson 7, "String Operators
and Functions," that string comparisons are not case sensitive unless you include the BINARY
keyword. In fact, BINARY is a collation type that tells MySQL to consider the underlying character
map values. The default collation for MySQL is not case sensitive, so it considers the character P to
have the same value as p when ordering.
The actual character sets available on your system depend on those supported by your operating
system. To see the character sets available, issue the SHOW CHARACTER SET command. The following
output shows just a few sample lines of outputyour actual output will vary.
The Maxlen column indicates the number of bytes required to store a character using each character
set. Some complex alphabets require 2 or 3 bytes per character.
To specify the default character set and collation for a new database, use the CHARACTER SET and
COLLATION attributes in the CREATE DATABASE statement. For instance, the following statement would
create a new database using a Greek character set and the greek_general_ci collation:
If you do not specify a collation with the COLLATE keyword, the default
collation for a character setas shown in the output from SHOW
CHARACTER SET will be used.
Altering a Database
The ALTER DATABASE statement enables you to change the characteristics of an existing database. Its
syntax is the same as the syntax of the CREATE DATABASE statement, and any CHARACTER SET or
COLLATE specification changes the behavior of an existing database.
For example, suppose you want to change greekdb to use the ASCII character set. You would issue
the following command:
Use the DROP DATABASE command to drop a database completely. Use this command with extreme
cautionyou cannot recover a dropped database unless you have a backup.
Dropping Databases
Similar to CREATE DATABASE IF NOT EXISTS, you can use DROP DATABASE IF EXISTS to suppress an
error if you try to drop a nonexistent database.
Managing Tables
Now let's look at how database tables are defined, altered, and dropped.
A column name can be up to 64 characters long and can contain any character. You must enclose
the column name in quotes (") or backticks (`) if it contains a space. A column name cannot be one
of the keywords listed in Appendix F.
The data type of a column determines what values it can hold and the maximum size of a stored
value. For instance, a column defined as VARCHAR(6) can contain text data up to 6 characters in
length. You will learn more about the MySQL data types in Lesson 16, "Designing Your Database.".
A column constraint is used to impose a restriction on the values stored in that column. For
example, a column defined as UNIQUE may not contain the same value more than once. If a
constraint is violated when you attempt an INSERT or UPDATE on the table, MySQL will return an error
and your SQL statement will fail.
Let's look at an example from the sample database. The following statement creates the products
table:
Although the formatting shown in this example is not necessary, it helps to show the different
elements of the column specification. You give the column a name, then its data type, and then any
constraints that are required.
CREATE TABLE
The CREATE TABLE statement has many different options, and there is
not space in this chapter to cover them all. Please refer to the online
MySQL manual at http://dev.mysql.com/doc/refman/5.0/en/create-
table.html for the full CREATE TABLE syntax.
In this table, the product_code column is defined as a 10-character string and is the PRIMARY KEY for
the table. Each table may have only one PRIMARY KEY because this is a unique identifier for each row
of the table. You will learn more about keys in Lesson 17, "Keys and Indexes.
Primary Keys
A PRIMARY KEY field also has the UNIQUE and NOT NULL constraints,
even if you do not specify them in the CREATE TABLE statement.
The other three columns are given the NOT NULL constraint. With this constraint, any attempt to
insert data rows where any of these columns are left empty will fail.
NULLs
The name column is a text field with a maximum length of 40 characters; it is specified as UNIQUE.
This is done to ensure that two products in the database will never have exactly the same name.
The weight and price columns are defined as DECIMAL(6,2). This is a 6-digit number with 2 of those
digits appearing after the decimal point. Therefore, the maximum value is 9999.99.
Data Types
This statement creates a simple table in which the value of the sex column will be Female unless you
specify otherwise.
Then insert a row that gives a value for only the name column, as follows. You will learn how to form
an INSERT statement in Lesson 15, "Working with Data."
Retrieving the data from this table shows that the default value was used:
Autoincrementing Columns
It is possible to specify a column in a table as an autoincrementing column. Such a column will
contain a number that is assigned automatically each time a new row is inserted. To do this, use the
AUTO_INCREMENT attribute on a numeric column.
The orders table in the sample database uses AUTO_INCREMENT on the order_id column to assign a
new order number each time an order is placed. The table definition is as follows:
If you insert a new record into this table without giving a value for the order_id column, its value
will be assigned as the next unused number in sequence.
The following query selects the two most recently added records from the orders table. As you can
see, the newly inserted record has an order_id that is one higher than the previous record.
A temporary table lasts only for the current MySQL session. Therefore, after you have disconnected
from the database, the table will no longer be available after you reconnect. To create a temporary
table, use CREATE TEMPORARY TABLE instead of CREATE TABLE.
Temporary tables are useful if you need to manipulate data using temporary storage within an
application and you do not want the tables you use to remain on the system when you are finished
with them.
A temporary table name can be used simultaneously in multiple MySQL sessions. Therefore, if two
instances of your program run at the same time, it is not necessary to generate a unique name for
the temporary table in each instance.
Using a Query to Create a Table
You can use the result of a query to create a new table by putting a SELECT statement inside the
CREATE TABLE command.
The following example creates a table that contains a subset of the customer_contacts table for one
customer. This is also created as a temporary table, so it will be destroyed when you end your
MySQL sessions.
The keyword AS is optional but can be included to make the command more readable. If you view
the structure of the new table, you will see that all the columns from customer_contacts are present.
Notice, however, that the contact_id column is no longer a PRIMARY KEY for the table and is not an
AUTO_INCREMENT column. Keys are not copied when you create a table using this method, but MySQL
does retain the data types of the columns and any NOT NULL constraints.
Storage Engines
MySQL supports several different storage engines that are used to handle different table types. The
storage engine can be specified in the CREATE TABLE statement using the ENGINE keyword to tell
MySQL how a table should be handled.
The default storage engine for MySQL is called MyISAM. Using this handler, tables are stored on disk
in three files, with extensions .MYI, .MYD, and .frm. An alternative disk-based table handler is
InnoDB, which supports some features that are not available in MyISAM such as transactions that
you will learn about in Lesson 15. Support for InnoDB must be enabled at compile-time for your
MySQL server.
The MEMORY storage engine is a very fast storage engine that stores tables in memory only. However,
because no data is written to disk, the contents of your tables are destroyed when the MySQL server
is stopped. MEMORY is usually used for temporary tables.
The following example creates a new table that uses the InnoDB engine:
When using a query to create a table, the ENGINE keyword must appear before the query. The
following statement uses the MEMORY engine for a temporary table that is created from a query:
You can use the ALTER TABLE command to change part of a table definition. You can ADD, MODIFY, or
DROP a column on a live table, although, of course, you should take care to ensure that doing so will
not cause errors in an application or query that relies on the existing table structure.
To add a new column, use the ADD keyword followed by a column definition. For example, the
following statement adds a new column named fax to the customer_contacts table, which has a
maximum length of 12 characters:
To modify an existing column, use the MODIFY keyword followed by the existing column name, a new
column name, and a column definition. You can use MODIFY both to rename a column and to change
its definition.
Suppose you realize that the fax column is not long enough to store international fax numbers, so
you want to make this an unlimited-length TEXT type column. The following statement changes the
data type of fax . Notice that the column name appears twice in this statement because you do not
want to change its name.
To drop a column from a table, use the DROP keyword followed by the column name. The following
statement drops the fax column from the customer_contacts table:
To drop a table, use the DROP TABLE command followed by the name of the table. Beware that a
dropped table cannot be recovered unless you have a backup.
To drop the people table you created earlier in this lesson, use the following command:
You can use DROP TABLE IF EXISTS so that no error occurs if a table does not exist. This is useful in
a batch script that creates all the tables for a database: The script will delete the existing tables
before re-creating them but will not fall over if the tables do not exist yet.
Summary
In this lesson, you learned how to use the Data Definition Language to create and modify databases
and tables in MySQL. In the next lesson, you will learn how to use the Data Manipulation Language
to work with data.
Lesson 15. Working with Data
In this lesson, you learn how to use the INSERT, UPDATE, and DELETE SQL statements to manage data
rows in your MySQL tables and load data from files.
The INSERT Statement
The subset of SQL that enables you to insert data and to update and delete existing records in a
table is known as the Data Manipulation Language.
The INSERT statement adds a new row of data to a table. At its simplest, INSERT is followed by a
table name, the keyword VALUES, and a list of values in parentheses that correspond to each column
in the table in turn.
The products table contains four columnsproduct_code, name, price, and weightso you can insert a
new product using the following statement:
The response from MySQL indicates that a row has been successfully inserted.
INTO
The INTO keyword is actually optional. However, you will usually see it
included in INSERT statements because it makes them more readable.
The second INSERT format requires you to specify the name of each column before giving the
valuesthis is known as a full insert. The following statement works the same way as the previous
example:
This might seem a little long-winded, but it means that you do not need to give a value for every
column in the table, or list the values in the correct order. One big advantage is that if the table
structure changes, the second example in this section will still work, whereas the first example will
fail because every column in the table is not given a value.
Column Mismatch
Notice that the second example used a different product_code value than the first. This is because
product_code is a PRIMARY KEY column and can contain only unique values. If you try to perform an
insert that violates a database constraint, you will see an error like the following:
NULL Columns
If you do not give a value for a column that has the NOT NULL
constraint and also does not have a default value, the insert will fail.
If you explicitly want to use a column's default value in an INSERT statement, use the DEFAULT
keyword as its value. In the following examples, you insert new record into the orders table, where
the order_id column has the AUTO_INCREMENT property:
Both formats of the INSERT statement perform the same job. You can then query the orders table to
verify that the two records were inserted with sequential order_id values.
The following statement inserts three new rows into the customers table:
If one of the rows in a multiple INSERT statement causes an error (for instance, a duplicate value in
a UNIQUE column), the insert will fail. The values are inserted in sequence, however, so rows before
the one that caused the error will have already been inserted into the database.
Atomic transactionsdatabase operations that all take place at the same timeare discussed in the
"Transactions in MySQL" section later in this lesson.
The format for this type of INSERT command uses a SELECT statement in place of VALUES. The
requirements of an INSERT must hold true: The query must return the correct number of columns for
the insert, and the insert must not violate any column constraints.
The following query inserts a new contact for each customer named Joe Soap. This is a trivial
example, but it demonstrates how this feature can be used with powerful results.
A new row in customer_contacts is inserted for each row in the customers table. The customer_code
column is populated from the customer_code value in customers, whereas first_name and last_name
are given static values; these are returned as is by the query and, therefore, are used as fixed
values in the insert.
Deleting
Without a WHERE clause, DELETE deletes every rows from the given
table. Unless this is the result you want, always make sure that you
include a WHERE clause in a DELETE statement.
To delete only a single row from a table, you should ensure that the WHERE clause will match only
that row. Usually, you should check the value of the table's PRIMARY KEY column to ensure that an
exact match is found.
The following example deletes one of the new products that you inserted in the previous section:
The response from the DELETE command indicates the number of rows that were removed. The
following example deletes several rows from the customer_contacts table using a WHERE clause that
finds all the customers with a given name. These rows will be the ones inserted in the section "Using
a Query to Insert Rows."
A DELETE cannot be undone unless it is part of a transaction that is rolled back. You will learn about
this feature in the "Transactions in MySQL" section later in this lesson.
The UPDATE Statement
The UPDATE statement is used to change one or some of the values in a data row. As with DELETE,
you include a WHERE clause to indicate that this row or rows are to be updated.
Updating
You specify the values to be changed in a list after the SET keyword, separated with commas. The
following example updates the name and price of an existing product:
The response from MySQL confirms that the update was successful and reports that one row was
changed. The numbers against Rows matched and Changed in the output might be different: The
former tells you how many data rows were matched by the WHERE clause, whereas the latter
indicates how many were altered from their previous value.
If you were to issue the previous statement again, you would see this output instead because the
column values are already the same as the values in the UPDATE statement:
This statement does not require a WHERE clause because you want the calculation to apply to every
row in the table. MySQL calculates the value of price * 1.10 for each row in the table and uses that
value to update the corresponding row.
The following example uses a subquery to set the prices for each product based on its popularity.
Each item's price will be set to $10 plus 10¢ for each time the product has been ordered.
Examining the products table will show that the prices have been updated and that each has a
different value.
mysql> SELECT * FROM products;
+--------------+-----------------------------+--------+-------+
| product_code | name | weight | price |
+--------------+-----------------------------+--------+-------+
| MINI | Small product | 1.50 | 13.60 |
| MIDI | Medium product | 4.50 | 11.00 |
| MAXI | Large product (new formula) | 8.00 | 14.80 |
+--------------+-----------------------------+--------+-------+
3 rows in set (0.00 sec)
The syntax for REPLACE is just like INSERT, or you can use the alternative syntax with SET , if you
prefer. The following examples both perform the same operation: to replace the MINI product with a
new description, weight, and price.
Replacing Rows
The output from the previous examples shows two rows affected
because two operations took place: one DELETE and one INSERT.
Loading Data from a File
You can load data from an external file into MySQL using the LOAD DATA INFILE command. The data
in your file must be in a structured formatthe default format is one record on each line, with values
separated by tabs.
The file shown in Listing 15.1 contains a file that could be loaded into the products table using the
following command:
Paths
If no path is given for the filename in LOAD DATA INFILE, MySQL looks
for it in the MySQL system directory.
The previous command works because the columns in the data file map precisely to the columns in
the products table. If you instead needed to specify the columns because the data file values were
in a different order or some were omitted, you could do this by giving a list of columns in
parentheses at the end of the command.
The following statement is identical to the previous example, using a full insert in the LOAD DATA
INFILE statement:
If your data file is not tab-separated, you must specify the separation method in the LOAD DATA
INFILE statement using the TERMINATED BY and ENCLOSED BY keywords.
Supposing that you have a comma-separated data file with each value enclosed in quotes, you
would use the following command to indicate the separation:
Line Terminators
If your data file does not use the newline character to separate
records, you can specify the line terminator using LINES STARTING BY
and TERMINATED BY .
Sometimes you will be working with a data file that contains one or more header lines. Often when
you extract data from another program, the first line of the output contains the column names used
in that program. Listing 15.2 shows an example of a comma-separated data file that includes a line
of headings.
"ProdCode","ProdName","ProdWeight","ProdPrice"
"BLUE","Blue product",3.0,13.99
"RED","Red product",3.5, 25.00
"GREEN","Green product",4.5, 6.50
To ignore one or more lines at the top of a data file, use the IGNORE keyword followed by the number
of lines and the LINES keywordyou must use the plural LINES even if you want to skip only one line.
The following statement successfully loads only the data records from Listing 15.2:
A transaction is a group of Database Manipulation Language statements that occur as a unit. Either
the entire transaction takes place and is committed to the database, or none of the attempted
changes is saved.
Transactions enable you to ensure data integrity when performing multiple database operations.
Consider a product database that includes the number of each item in stock. When a customer
places an order, a record is inserted into the orders table for each product ordered, and the
corresponding stock levels are decreased.
Both of these changes to the database need to take place in a single transaction. Otherwise, two
possible pitfalls could be encountered.
If the items are added to a customer's order before the stock levels are decreased, there will be a
period of timealbeit usually only a fraction of a secondduring which another database user could
query the stock levels of a product and see the wrong value.
Although both of these pitfalls are extremely uncommon, the severity of the data corruption if one
occursparticularly where financial data is involvedmeans that transactions are essential to make
sure both actions happen as a unit.
Transactions in MySQL
Transactions in MySQL are available only on tables that use the InnoDB or BDB storage engines.
See Lesson 14, "Creating and Modifying Tables," for more information on how to select a specific
table handler.
Until you issue a statement that ends a transaction, the effects of any commands that you enter are
visible only within the current MySQL session. For instance, if you delete rows from a table after
issuing the START TRANSACTION command, other database users can still query those rows, even
though in your session they appear to be already deleted.
To commit all the changes made in a transaction, issue the COMMIT command. Doing so causes each
INSERT, UPDATE, and DELETE statement that forms part of the transaction to be executed
immediately and as one unit.
Autocommit Mode
By default, the system variable AUTOCOMMIT is set to 1, which instructs MySQL to process each
database-manipulation statement issued immediately as a single transaction. This is the behavior
you have already seen, with an INSERT, UPDATE, or DELETE committed to the database as soon as
you issue the command.
UPDATE PRODUCTS
SET price = 5.99
WHERE code = 'MINI';
When autocommit mode is turned on, the previous statement is executed as if you had entered the
following:
BEGIN TRANSACTION;
UPDATE PRODUCTS
SET price = 5.99
WHERE code = 'MINI';
COMMIT;
By setting the value of AUTOCOMMIT to 0, you disable this feature so that you have to use COMMIT to
store any changes madeor use ROLLBACK to discard changessince the beginning of the transaction.
You can also end a transaction without committing the changes with the ROLLBACK command. The
result is that the database state is rolled back to how it was before you issued the START
TRANSACTION command.
The following example shows how you can recover from a disastrously wrong DELETE
statementremember to always include the WHERE clauseif it occurs within a transaction:
mysql> ROLLBACK;
Query OK, 0 rows affected (0.01 sec)
If you then query the products table, you will see that it still contains records.
If you try to use transactions with tables that do not use the InnoDB
storage engine, MySQL will not give an error when you START
TRANSACTION.
Now that you know how to create database tables and manipulate data, it'stime to take a look at
the principles of relational databases and see how to apply good design practices to your own
databases.
Data in a relational database is split across several tables in a structured way. Relationships are the
rules that determine how data in one table is related to data in another. When you join tables in
SQL, you specify the relationship between the tables in the query. Refer to Lesson 11, "Joining
Tables," for more information on joins.
Consider the relationship between two tables in the sample database. The orders table is related to
customers. Each record in the orders table contains a customer_id, which is a foreign key column
that corresponds to the primary key in customers.
Therelationship between customers and orders is known as a one-to-many relationship because one
row in the customers table can be related to many rows in the orders table. Think of what the
database is trying to achieve herea customer must not be limited to placing only one order!
Many-to-One
The relationship between products and orders is a many-to-many relationship. An order can contain
the same product many timesalthough the quantity column should help to avoid the need to do
thisand, of course, each product can appear on many orders.
In the sample table, the many-to-many relationship between products and orders is actually
implemented using two separate relationships and the order_lines table. There is a one-to-many
relationship between orders and order_lines, and also a one-to-many relationship between
products and order_lines.
As you might expect, a one-to-one relationship is also possible, although there is no relationship of
this kind in the sample database. A one-to-one relationship uses a key that is unique in both tables;
therefore, the data could actually be stored in one table instead of two.
Usually you use a one-to-one relationship for performance reasons. For example, you could keep
one table highly optimized by storing only the most commonly used columns. The second table
would contain larger amounts of data and would be joined to the first only when those columns
were required. In particular, you can often improve performance by separating large text or binary
data columns from the body of a table using a one-to-one relationship.
Normalization
Normalization is the process of optimizing the relationships between tables in your database. The
process involves several stages of splitting a database into smaller components and adding the
appropriate relationships.
Many reasons exist for normalizing your database from the outset. Normalization helps to improve
the performance of the database by using only the most efficient relationships between tables. It
also improves maintainability by reducing repetitive data.
The first stage of normalization involves eliminating any columns that might contain multiple values.
For example, consider the following table. This shows a variation on the customers table that also
includes the data that is in the customer_contacts table.
As you can see, the contacts column contains multiple names, separated using commas. This type
of table structure must be eliminated.
Notice also that this structure enables you to store only a contact name. Another approach is to
have one row in the customers table per contact. This satisfies the requirement of not having
multiple values in a column, but this structure will include a lot of duplicated data, as shown in
Figure 16.2.
You should remove duplicate rows by creating a related table; this is howthe customers and
customer_contacts tables are constructed in the sample database you have been following in this
book.
The customer_code column is a primary key for customers and a foreign key for customer_contacts,
with a one-to-many relationship. This structure ensures that each customer record appears only
once in customers but that each customer_code can appear many times in customer_contacts; in this
way, many contact names are added for each customer.
The normalized tables from this part of the database are shown inFigure 16.3
Now let's look at some of the database design issues to considerwhen creating tables in MySQL.
The names you give your tables and their columns are importantchoose them carefully. First and
foremost, the names you use should be clear identifiers. Table name should indicate what data is
being stored, and column names should identify what their values represent.
For example, the products table does exactly what you would expect: It contains details of the
products in the database. The purposes of columns named weight and price in this table are
obvious as well.
You can adopt many different naming conventions. No one convention in particular is correct, and
the one you choose to use will be a matter of preference, but you should try to retain a consistent
namingscheme throughout your database.
In the sample database, table names are always plural (customers, products , and so on), but you
might prefer to use singular nouns (such as customer and product) as the table names.
For both table names and column names, the sample database uses an underscore character to
separate words, as in the order_lines table or the product_code column. Another popular
convention is to capitalize the first letter of each word, as in ProductCode or sometimes productCode.
Case Sensitivity
Table names in MySQL are usually case sensitive, so you must always
use the same capitalization when referencing tables. On Windows
systems and other platforms where the directory names on the file
system are not case sensitive, table names are not case sensitive.
Column names are not case sensitive on any platform, but you should
still try to keep a consistent capitalization to maintain readable code.
Sometimes you will come across systems in which the table identifiers contain a prefix or suffix to
indicate that they are, in fact, a table, such as tblProducts or products_tbl. Other types of database
objects might have their own naming scheme, such as an idx prefix or suffix for indexes.
Columnnames might even contain a reference to the table name, such as prodWeight. These
conventions sometimes aid the readability of an SQL statement by ensuring that the purpose of an
identifier is absolutely clear.
Database and table identifier names can contain any character except ., \, and /. Because MySQL
writes tables to disk using the names you provide, characters that can have special meanings in a
filename are disallowed. A column name may use any character.
Forexample, the following CREATE TABLE statement is perfectly validin practice, however, the poor
choice of identifier names would render it unusable:
Data Types
For a complete list of the data types you can use, refer to Appendix
D, "MySQL Data Type Reference," which can be found on the book's
website at www.samspublishing.com.
INTEGER
An integer is a whole number. The range of values that can be stored in an integer data type
depends on the size of the integerMySQL has five different sizes:
Unsigned Values
In the sample database, quantity is defined as TINYINT UNSIGNEDit is expected that no single order
will include more than 255 of the same product. The column is declared UNSIGNED because it is
nonsense to allow a negative quantity.
DECIMAL
DECIMAL is an exact, fixed-point number. It is declared as DECIMAL(M,D), where M is the total number
of digits and D is the number of digits after the decimal point.
In the sample database, we used DECIMAL for both the weight and price columns on the products
table. Each was declared as DECIMAL(6,2), meaning that the largest value that could be stored in
each is 9999.99six numbers in total, with two appearing after the decimal point.
CHAR and VARCHAR
CHAR and VARCHAR are character data types. You give a maximum length in parentheses when
specifying the column; if you attempt to insert a value longer than the maximum length, it is
truncated.
A CHAR column has a fixed length, and values shorter than the maximum length are padded with
spaces when stored. When you retrieve the value from a CHAR column, however, the trailing spaces
are removed. The storage requirement for a CHAR column is simply 1 byte per character in the
padded stored value.
A VARCHAR column has a variable length. Its storage requirement for each row depends on the length
of the data item it contains1 byte for each character is required, plus 1 byte that stores the value's
length.
You might use a CHAR(2) column to store the two-letter state code in a person's address. In the
sample database, we used VARCHAR(40) for a product's name. Forty characters should be more than
enough.
Maximum Lengths
You should always take care to ensure that a CHAR or VARCHAR is long
enough for any data you can foresee the column holding. If you
attempt to store a value longer than the maximum length, it will
simply be truncated with no warning.
A BLOB is a binary large object that can contain a variable amount of data. TEXT is a similar data type
for character data. Both types have the following variations:
TEXT and BLOB have a maximum size of 65,535 characters or bytes (64KB).
MEDIUMTEXT and MEDIUMBLOB have a maximum size of 16,777,215 characters or bytes (16MB).
LONGTEXT and LONGBLOB have a maximum size of 4,294,967,295 characters or bytes (4GB).
You can use a TEXT column to store free text data, such as a comments field. A BLOB column can be
used to store true binary data, such as an image or sound clip, as well as free text data that you do
not want to be stored using a character set.
The DATE data type in MySQL stores date values in the format YYYY-MM-DD. The DATETIME data type
also includes a time element, in the format YYYY-DD-MM HH:MM:SS.
Date Validation
A date column does not perform any validation itself beyond checking
that the format of a value meets the stated criteria. It is actually
possible to store nonsense dates, such as 2005-02-29 or even 2005-
99-99, in a date column.
The TIMESTAMP column type has a special property: Its value takes the current date and time
whenever you insert a new row or update an existing row, unless you specify another value for the
column.
TIMESTAMP columns are useful in tables for which you want an audit trail of when records were last
inserted or updated. You do not need to build the time tracking into your applicationsimply let
MySQL do the work.
Summary
In this lesson, you learned some of the principles of database design that you should apply in your
own applications. In the next lesson,you will learn how to use indexes in MySQL.
Lesson 17. Keys and Indexes
In this lesson, you learn what indexes and keys are, and discover how indexing data on a key field
can speed up data access times.
Understanding Keys and Indexes
The terms keys and indexes are often used interchangeably. A key column stores values that are
used to filter rows in the table, either in the WHERE clause when querying that table or as part of a
join to indicate the relationship between two tables.
A key column in MySQL is always indexed, but you can create an index on any table column or on
multiple columns.
Primary Keys
Each table can contain only one primary key, which is a unique identifier for each row in the table.
Often the primary key is an AUTO_INCREMENT column so that a new unique number is assigned
automatically for each row added to the table.
You can be sure that when you query a table using a filter on a primary key field, MySQL will return
only one row for each match in the filter.
An incremental ID number makes a good primary key. A unique character codesuch as product_code
in the sample products tablecan work well, too, as long as you can ensure that the value will always
be unique.
You should not use a person's name as a primary key because there is always a chance, however
rare, that you could get a duplicate record. If you attempt to insert a duplicate value into a primary
key column, a key violation occurs and MySQL gives an error.
Foreign Keys
A foreign key is a column that another table references. When you join two tables, the join condition
usually is that the primary key from the first table must be equal to a foreign key in the second.
In the sample database, the foreign keys have the same name as the corresponding primary keys in
their related tables. For instance, products. product_code is a primary key that is referenced by
order_lines.product_codeeach line of an order refers to exactly one product using a unique identifier
for the product.
Foreign Key Constraints
If you use the InnoDB table handler, you can add foreign key
constraints at the database level to maintain referential integrity. You
will learn how to do this in the section "Foreign Key Constraints with
InnoDB," later in this chapter.
Indexes
Although there can be only one primary key on a table, you can create indexes on other columns in
a table for performance reasons.
When MySQL searches for a value in a table column, if there is no index, it must start with the first
row and check each row until it reaches the end of the table. However, when an index is available,
the process is much quicker: The index tells MySQL where to look within the table for rows
corresponding to that key value.
The more rows there are in a table, the bigger the impact a key can have on queries that return
only a small number of rows from that table.
You can define a column as a UNIQUE KEY if you are sure that its values will be unique. Queries using
a UNIQUE KEY are faster than a non-unique key because MySQL knows that only one matching row
will be returned from the table.
Using Indexes in MySQL
You can define a column that will be indexed in MySQL when you create a new table as a clause in
the CREATE TABLE statement, or on an existing table using the CREATE INDEX command.
A primary key is specified using the keywords PRIMARY KEY followed by the name of the column in
parentheses. You can also specify a UNIQUE KEY or UNIQUE INDEX, or simply a KEY or INDEX with no
further constraints. The column name is given in parentheses after the key type.
The following statement shows an alternative CREATE TABLE statement for the products table in the
sample database. The table it creates is the same as if PRIMARY KEY were specified alongside the
product_code column and the name column was given the UNIQUE attribute.
You can use the ALTER TABLE command to add indexes to a table using this syntax in the same way
you would add new columns to a table. The following example defines a new index on the
customer_code column in the orders table:
Although it is not necessary for the sample tables that contain only
very few rows, the previous example creates an index that would
probably speed up database access on the orders table when it
contains a large number of rows. The index could be used when you
either query orders for a particular customer or join orders to the
customers table.
The following statement creates the same index you created in the previous example on
orders.customer_code. The index is named cust_code_idx .
If you execute both this statement and the previous example, you will not see an errorMySQL will
create two indexes on the same column of the same table. However, because each index name
must be unique, you will generate an error if you try to execute this CREATE INDEX statement again.
The following example shows the indexes on the orders table. The output shown assumes that you
executed both of the previous two examples, so the index on customer_code was created twice.
The output shown here has been modified because of space constraints in this book. The actual
output you will see contains a few other columns.
The first row contains the primary key for the table. The other rows are the additional indexes you
created. The one created through the ALTER TABLE statement was given the name customer_code ,
shown in the Key_name column. The Non_unique column contains 0 for the primary key and 1 for the
other keys, which were not created with UNIQUE.
Duplicate Indexes
Although MySQL does not generate an error if you create the same
index twiceas long as it does not have the same namethere is never a
reason to do this. MySQL can use only one index, so the second
simply takes up extra disk space. We drop one of the unnecessary
indexes on this table in the next section.
Dropping Indexes
To drop an index from a table, you need to know its name, which you have to check using the SHOW
INDEXES command unless you specified the name yourself.
The following command drops the cust_code_idx index using the DROP INDEX command, leaving all
other indexes and all the data in the table intact:
Alternatively, you could use the ALTER TABLE command with DROP INDEX. The following statement
would perform the same operation as the previous example:
The only time you do not need to know the name of an index is when
it is the primary key on the table. Then you can use ALTER TABLE
tablename DROP PRIMARY KEY.
Partial Indexes
When creating an index on a string value, you can tell MySQL to use only part of the value rather
than the whole string in the index. The following statement creates an index on the name column in
the customers table, but using only the first five characters of the name:
A partial index can be useful when you index columns that can potentially contain large values. The
index will have a smaller storage requirement while still assisting queries in finding values from the
column quickly.
MySQL compares the specified number of characters in the key to locate matching rows first. If
more than one row matches the partial key, it checks those rows to find an exact match.
Compound Indexes
You can specify two or more columns when creating an index, and MySQL will create an index that
uses the values from both columns in the order given. This is known as a compound index.
The following statement creates a compound index on the weight and price columns in the products
table:
Usually you create a compound index on two columns that are frequently used in a single query or
are both used in a table join. MySQL can use only one index on each table in a query, so two
separate indexes on the same two columns cannot both be used.
The index created by the previous example could speed up a query on the products table that had a
filter on both weight and price. Additionally, because weight is the first column specified, this index
could be used effectively on queries that filter just on weight. However, it would be ineffective on
queries that filter on price only.
You specify a full-text index using the FULLTEXT keyword in the table definition or on an existing
table using the ALTER TABLE statement. The following statement adds a full-text index to the
customer_contacts table on the first_name and last_name columns:
The MATCH() function works only with columns that have a full-text index. You specify the column to
search in parenthesesif you have more than one full-text index, you can specify a list of
columnsfollowed by the keyword AGAINST and a list of values to search for.
The following example searches the customers table for a name that matches the string
Corporation:
The full-text index feature is available only using the MyISAM storage
engine. You cannot use FULLTEXT with an InnoDB table.
For example, a foreign key on the customer_code column in the orders table that references
customers.customer_code would ensure that you can enter rows into orders only for customers that
are already in the database.
The sample tables do not have their foreign keys enforced at the database level, to ensure that they
work on systems on which InnoDB is not available. The following example shows how the CREATE
TABLE statement for orders would be amended to include this constraint:
To create a foreign key constraint, both the table with the constraint
and the table that it references must use the InnoDB storage engine.
The previous example will fail if the customers table is a MyISAM
table.
The following example attempts to insert a new row into the orders table and shows the error
message that is displayed when the foreign key is violated:
Consider what might happen if you delete a record from the customers table for which there are
corresponding rows in orders. The records in the orders table would then violate the foreign key
constraint.
To avoid this, you can specify an action to take when values referenced by a foreign key are
changed or removed using the ON UPDATE or ON, DELETE keywords in a FOREIGN KEY clause. The
possible values are as follows:
CASCADEWhen a referenced value in the parent table is updated, corresponding rows in the child
table have the same update performed on their foreign key columns. If the value in the parent
table is deleted, rows in the child table are automatically deleted when a foreign key is deleted
from the parent table.
SET NULL When a referenced value in the parent table is updated or deleted, corresponding
rows in the child table have their foreign key columns set to NULL. This action is not possible if
the foreign key column has the NOT NULL constraint.
NO ACTIONRecords will never be modified or deleted in the child table. Instead, if an UPDATE or
DELETE on the parent table would change or remove a referenced value, the action is
prohibited. This is the default action if no ON UPDATE or ON DELETE action is given.
The following statement can be used to add the foreign key described in the previous example to
the customers table, using CASCADE for updates and NO ACTION to prevent referenced columns from
being deleted from the parent table:
ALTER TABLE orders
ADD FOREIGN KEY(customer_code)
REFERENCES customers(customer_code)
ON UPDATE CASCADE
ON DELETE NO ACTION;
Then, if you update a record in the customers table, corresponding rows in orders will be updated
with the same customer code.
However, attempting to remove a referenced row from the customers table is prohibited and gives
an error, as shown in the following example:
MySQL has a sophisticated multiuser access-control system that can allow or prevent each user
from having access to a particular database or individual tables. You can even restrict the types of
operations the user is able to perform on a table.
Web Access
When MySQL is used as the back end to a website, you will usually
have only a single user account through which all the connections
from the web scripts are performed. Your application will handle any
additional user authentication that is required in the web browser.
localhost
Often you communicate with MySQL only from localhostthat is, when
you run the mysql client on the same machine as the MySQL server,
or you access a database from an application or web script that is
running on the same machine.
Not only do you need to supply a valid username and password for the database you want to gain
access to, but you also need to satisfy MySQL that you are connecting from an allowed host for that
user. If you try to connect with a username and password that are not valid for the host you are
connecting from, access will be denied, even if the login information works from another host.
It is also possible for two users who have the same username but are connecting from two different
hosts to use separate passwords and have separate privileges. Therefore, you should try to think of
a MySQL user as a username plus a host when dealing with user permissions, rather than just the
username. In other words, consider the access requirements for chris@localhost or
chris@192.168.1.100, not for user chris.
MySQL Privileges
MySQL includes a number of individual privileges that determine the type of actions that a user can
perform. For example, a user with the SELECT privilege may query a table, but the same user also
requires the INSERT, DELETE, and UPDATE privileges to perform data manipulation on the same table.
A privilege can be granted to a userremember, this means a user plus a hostat the table level.
Therefore, two users with access to the same database can be given permission to use only the
tables they require access to.
Table 18.1 lists the privileges that can be assigned. User permissions are set using the GRANT and
REVOKE commands, which are discussed later in this chapter.
Superuser
Data from the user table is used for authentication. The Host, User, and Password columns contain
the values used to validate a connection attempt. The Password column is encrypted, so you cannot
view a user's actual password by querying this table.
The db database contains the default permissions that a user has for each database. The Db, User,
and Host columns are followed by a series of privilege columns, such as Select_priv and
Alter_priv. Those columns contain either a Y or an N value to indicate whether that privilege has
been granted.
Individual table privileges are stored in the tables_priv table, using the Db, User, Host, and
Table_name columns to identify the database table and user. The Table_priv column contains the
name of the privilege granted. Whereas db contains one row per user and database, there is one
row in tables_priv for each table-level privilege assigned.
Changing Privileges
Creating a User
Use the CREATE USER command to create a new user. The username given should be a username and
a host, in the format user@host. Include the keywords IDENTIFIED BY to set a password for the new
user.
Passwords
If you do not assign a password for a user, that user will be able to
connect to MySQL without even supplying a password.
The following example creates a new user named chris that can connect only from localhost, with
the password mypass:
You usually create new users when connected to MySQL as the root user, but if you want to allow
other users to use the CREATE USER command, you should assign them the INSERT privilege on the
mysql database. The underlying operation is an INSERT command that adds a record to mysql.user.
You can use the SET PASSWORD command to reset a user's password, but you must use PASSWORD() to
produce the encrypted password as part of this command. The following is an example:
mysql> SET PASSWORD FOR chris@localhost = PASSWORD('newpass');
Query OK, 0 rows affected (0.00 sec)
If you omit the PASSWORD() function, MySQL warns you that you did not supply a valid password.
Any user can use SET PASSWORD, although only a superuser can change other users' passwords. To
change the password for the logged-in user, omit the FOR user part, as follows:
Granting Privileges
To assign a privilege to a user, use the GRANT command. This can be done through an individual
privilege, a list, or the ALL PRIVILEGES keyword, which allocates every privilege shown in Table 18.1
to the user.
The following example grants the SELECT and INSERT privileges on the products table in the mysql10
database to the new user chris@localhost:
If you connect as this user, the SHOW TABLES command reveals just one table; tables you do not
have the SELECT privilege for are not displayed.
Passing on Privileges
When you grant a privilege to a user, that user will be able to take advantage of the new access
rights but cannot pass that privilege on to another user unless you specifically grant permission to
do so.
To do this, use the keywords WITH GRANT OPTION in a GRANT statement. The following statement
allows chris@localhost not only to query the products table, but also to use the GRANT command
himself to give the SELECT privilege to other users:
Even though only the SELECT privilege is named in the previous statement, WITH GRANT OPTION allows
this user to grant any privileges he possesses to another user.
Revoking Privileges
The opposite of granting a privilege is revoking, performed using the REVOKE command. Its syntax is
similar to GRANT, as shown in the following example, which removes the INSERT privilege that was
granted in the previous section.
mysql> REVOKE INSERT
-> ON mysql10.products
-> FROM chris@localhost;
Query OK, 0 rows affected (1.25 sec)
Only the INSERT privilege is revoked; the SELECT privilege that was assigned to this user at the same
time as INSERT is unaffected.
Using Wildcards
You can grant privileges to usernames that match wildcard criteria by using the % and _ wildcard
characters in the username.
You might actually want to create a user that can access the database from any remote host using
the same username and password without needing to create a separate username for each possible
host. Using % as the host part of the username accomplishes this, as shown in the following
example:
Wildcard Usernames
If you want to grant access only to a user from a particular range of IP addresses, you could use a
statement like the following:
In this case, the user would be authenticated only if connecting from an IP address in the range
192.168.1.10 to 192.168.1.19.
The following example shows the privileges for chris@localhost that were set up throughout this
lesson.
Notice that this output does not contain each GRANT statement issued for the user, and does not
contain any REVOKE statements. After revoking INSERT, the user has only the SELECT privilege.
Deleting a User
To completely remove a user, in MySQL 5.0.2 and above you can use the DROP USER command, as
shown:
In earlier versions of MySQL, you must revoke the user's privileges first and then manually delete
the appropriate record from the mysql.user table. The following example shows the steps required to
reproduce the previous DROP USER command:
Dropping Users
To use the DROP USER command, you must have the CREATE USER
privilege if you are not a MySQL superuser. To delete the user using
the manual method, however, you must have the DELETE privilege for
the mysql.user table.
Summary
In this lesson, you learned how to manage users and control their access to MySQL databases using
the privilege system. In the next section of the book, you will learn how to use some of the new
features of MySQL 5.0.
Part 5: New Features in MySQL 5.0
Lesson 19. Views
Views are a tool of convenience. For example, if you find yourself frequently performing the same
join, you might find it more convenient to create a view to use in your queries instead.
Creating a View
You create a view with the CREATE VIEW command. The following example creates a simple
viewevery column from the customer_contacts table is included, but a WHERE clause restricts the
rows returned to only those with the given customer_code .
The command executes silently if there is no error. An error in the SELECT statement of a CREATE
VIEW command produces the same error you would get if you had executed the query directly.
After you have created a view, you can perform a SELECT statement using it, as follows:
The output contains only the rows that were filtered in the CREATE VIEW statement. Other rows from
the customer_contacts table cannot be accessed using this view.
Views Are Not Tables
The following example creates a view that includes a table join on the customers and
customer_contacts table. This time, the CREATE VIEW statement also specifies a list of columns and
includes an expression.
An alias is required for the CONCAT() expression, to give that column a name in the view. Showing
the columns in this view reveals that there is indeed a column named full_name:
Where you use a derived column in a view, you must give the column
an alias; otherwise, you will not be able to select its values by name.
The name assigned if you do not give an alias will be based on the
expression used to calculate the column.
You must also use aliases if the SELECT statement in a view will return
two columns with the same name. MySQL returns an error if the
column names in a view are not unique.
Go ahead and select values from this columnyou will see that the concatenated full name is returned
for each value in the table.
View Naming
The name of a view must be unique across both views and tables. A
view cannot have the same name as a table in the same database.
Using Views
You must also have the SELECT privilege on all the tables that are referenced in the SELECT
statement of a CREATE VIEW statement. If you cannot query the tables yourself, you cannot create a
new view that uses them.
You can, however, grant the SELECT privilege on a view you created to another user without giving
that user the SELECT privilege on each table in the view. For instance, a system user could have
access to the customer_details view without being able to query either customers or
190customer_contacts directly.
Updating Views
Some views are updateable, but you cannot always use a view in an UPDATE, INSERT, or DELETE
statement. Several features of the underlying query that would cause a view to be nonupdateable.
If the view contains a join, you can usually perform a SELECT only on the view. MySQL cannot insert
into two tables simultaneously, even with the relationship between the tables specified in the join
condition.
You can insert into a view that uses a join only if it is an inner-join and also only if all the columns
you insert into are from the same table.
You cannot insert into any view that uses the UNION or UNION ALL operator.
A view cannot be updated, even if it is based on only one table, if its query contains any of the
following features:
A GROUP BY clause
The view's algorithm is TEMPTABLEsee the section "View Algorithms" later in this lesson for more
information.
Cascaded Views
The output of SHOW CREATE VIEW is designed to give you a single command that can be run on any
MySQL server to reproduce that view. The following shows this for the customer_details view:
Showing Views
Because views behave just like tables, the SHOW TABLES command will
show all your views as well as your tables.
View Algorithms
The output from the previous example included an optional attribute in the CREATE VIEW statement:
ALGORITHM=UNDEFINED. This attribute is a MySQL-specific extension to the SQL language used to
instruct MySQL on how to process a view. When this is UNDEFINEDwhich will be the case unless you
explicitly give an algorithmMySQL chooses the algorithm.
The MERGE algorithm is usually the most efficient way for a view to be processed. The underlying
SQL is merged into the SQL statement, and the query is executed in one go. Consider the following
query using the custview view:
If the custview view is executed using the MERGE algorithm, the query is actually executed as if you
entered the following:
However, if custview uses the TEMPTABLE algorithm, the process would be as if you had executed the
following steps:
The TEMPTABLE algorithm must be used if the query contains an aggregate function, a GROUP BY
clause, the DISTINCT keyword, or a UNION.
A stored function is a stored routine that can return a value to SQL. A useful feature is the capability
to define libraries of functions so that you can perform an operation on your database from any
client program. Libraries of commonly used functions and procedures help reduce code duplication
and make your systems easier to maintain.
Function Libraries
If you use multiple APIs to communicate with your database, you can
execute the same function from each language without having to
rewrite the function.
The following is a very simple example. The procedure created, named yesterday, takes no
arguments; it simply selects and displays the date and time precisely 1 day ago.
To execute a procedure, use the CALL command. The following shows typical output from the
yesterday procedure:
Note that both the procedure definition and the CALL command include a set of parentheses after
the name of the procedure. The parentheses are used to pass optional arguments to a procedure,
but they must be included even if no arguments are required.
The following example creates a new procedure named longdate that displays a given date value in
a predefined format:
When you call this procedure, you must supply a date argument in the parentheses, as in the
following example:
Note that procedures do not return a value; to do that, you must use a function. Therefore, you
cannot nest these two procedures (for example, to use yesterday as an argument to longdate ). Both
functions simply perform a SELECT statement, and their output is displayed in the mysql monitor.
The real power of stored routines lies in their capability to execute many different SQL commands in
a single procedure call. When a procedure contains more than one SQL statement, you must use the
BEGIN and END keywords around the procedure body.
The following example is a procedure that applies a given percentage increase to all the prices in
the products table, and then displays the new average price for all products:
Before you attempt to create this procedure in MySQL, consider that the semicolon characters within
the procedure are intended only to terminate the individual SQL statements, not the CREATE
PROCEDURE command. This creates a conflict that must be worked around.
To keep the mysql program from treating the semicolons within a function as terminators for the
CREATE PROCEDURE command, you must define a new terminator character using the delimiter, or \d,
command.
Delimiter Characters
The following example sets the delimiter to // before creating the new procedure:
mysql> delimiter //
mysql> CREATE PROCEDURE price_hike (increase FLOAT)
-> BEGIN
-> UPDATE products
-> SET price = price * (1+(increase/100));
->
-> SELECT CONCAT('Average price is now ',
-> AVG(price)) as new_price
-> FROM products;
-> END
-> //
Query OK, 0 rows affected (0.00 sec)
Using Delimiters
Bear in mind that after the delimiter has been redefined, you must
use that character until you specify a new delimiter or begin a new
mysql session.
The following example shows how the yesterday procedure from the previous section can be
implemented as a function:
Functions always return a value, so you must always give a return data type. The RETURN keyword is
used to prefix a value or expression for the return value.
The return type for this function is set as DATE, so any SQL statement that calls the function will
treat its result as a date value. Therefore, you can use the result from the yesterday() function as
an argument to the longdate procedure.
Routine Names
Only IN arguments are possible with a functiondata is naturally passed out of the function via the
return valueso the IN keyword is not required in the argument list.
The following example creates a function named order_total() that takes an order_id argument
and returns the total value of the items that make up that order:
mysql> delimiter //
mysql> CREATE FUNCTION order_total(id INT)
-> RETURNS DECIMAL(7,2)
-> BEGIN
-> DECLARE total_price DECIMAL(7,2);
->
-> SELECT SUM(ol.quantity * p.price) INTO total_price
-> FROM order_lines ol, products p
-> WHERE ol.product_code = p.product_code
-> AND ol.order_id = id;
->
-> RETURN total_price;
-> END
-> //
Query OK, 0 rows affected (0.00 sec)
You can then call order_total with a valid order_id value, as follows:
Using Variables
The DECLARE instruction in the order_total() function declares a variable named total_price,
defined as type INT .
You can use variables to store the result from a SQL queryin order_total() , the result of the query
was assigned by a query using SELECT ... INTOor by using SET to assign a value to a variable.
Variables declared within a stored routine have local scope only and cannot be referenced outside
the particular procedure or function in which they exist. In order_total() , the variable was required
only to return the result of the query from the function.
MySQL also supports session variables, which have global scope for the duration of the current
MySQL connection. Session variables do not need to be declared; their names are simply prefixed
with the @ symbol whenever they are required.
The following example creates a procedure named store_time that assigns the current time into the
session variable @time:
After you have called store_time in a MySQL session, you can use @time in any SQL statement to
reference this value. This variable retains the time that the store_time procedure was last called:
If you disconnect from MySQL and reconnect, the values of any session variables you have set up
are lost. The value of @time will be NULL if you have not called store_time in the current session.
Database-Level Routines
You can call a procedure or function from a database other than the
current one by prefixing the routine name with the database name.
Any SQL executed by the routine will be performed on the database
to which that routine belongs.
To view the body of a procedure or function, use the SHOW CREATE PROCEDURE and SHOW CREATE
FUNCTION commands. The following shows a sample output:
RETURN total_price;
END
1 row in set (0.00 sec)
Dropping a Stored Routine
To drop a stored routine from the database, use the DROP PROCEDURE and DROP FUNCTION commands.
As with other DROP commands, you can include the IF EXISTS keywords to avoid an error if you
attempt to drop a function that does not exist.
To create a new routine, a user needs the CREATE ROUTINE privilege. To modify or delete a routine, a
user must have the ALTER ROUTINE privilege. These privileges always apply to both procedures and
functions.
A user must have the EXECUTE privilege to execute a stored procedure. As the creator of a stored
routine, you have this privilege automatically. However, you grant other users access to your
routine manually.
You must indicate in the GRANT command whether the routine is a procedure or a function. The
following statement allows the user chris@localhost to execute the order_total() function:
Each trigger is associated with a table. You can create a trigger that will fire when an INSERT,
UPDATE, or DELETE takes place on the named table.
REPLACE
To create a new trigger, use the CREATE TRIGGER statement. You must give the trigger a unique
name and then provide the timing, action, and table that will cause the trigger to fire. For example,
to create a trigger that will fire every time a row is deleted from the products table, you would
construct a trigger as follows:
The timing for a trigger can be BEFORE or AFTER, indicating whether the trigger code should be
executed immediately before or immediately after the SQL statement that causes the trigger to fire.
The keywords FOR EACH ROW are part of the CREATE TRIGGER syntax and are required in every trigger.
If the trigger body contains more than one line of code, you must enclose the SQL statements with
the BEGIN and END keywords. As with stored routines, you also need to redefine the delimiter
character if the trigger body contains multiple statementsrefer to Lesson 20, "Stored Routines," for
more information.
When a trigger is activated, the stored code can access the data record that caused the trigger
event to occur. You can reference two pseudotables in the trigger body. Use OLD to reference
deleted values and the previous values from an updated row. Use NEW to reference the new values in
the database when using UPDATE or INSERT.
This example creates an audit trail on the products table. First, however, a new audit table must be
created to record the changes as they are made. The table should be created using the following
statement:
CREATE TABLE products_audit (
audit_date TIMESTAMP,
audit_user VARCHAR(40) NOT NULL,
audit_action ENUM('update','delete'),
product_code VARCHAR(10) NOT NULL,
name VARCHAR(40) NOT NULL,
weight DECIMAL(6,2) NOT NULL,
price DECIMAL(6,2) NOT NULL
);
Two triggers are required to log both DELETE and UPDATE actions on the products table. Each trigger
will store a copy of the previous record to the audit table, along with the date and time and the user
who issued the SQL command.
The trigger will fire whenever a row is deleted from products, and it will take place immediately
before that row is actually deleted. The OLD pseudotable allows the trigger code to access the old
values before they are deleted.
If you delete the MIDI product from the database, a new record will be created in the audit table
containing its former values.
This trigger implements a dynamic pricing system for the products table, based on supply and
demand. The rules for this example are fairly crude: Whenever an order is placed for a product,
increase its price by 1% for each unit ordered and decrease the price of the least popular product by
the same amount. Of course, you will need to make sure that this rule will not cause a product's
price to drop to 0 or become negative.
1. Whenever a new record is inserted into order_lines, calculate 1% of the price multiplied by
the quantity sold.
3. Find the product with the fewest sales and reduce its price by the same amount.
mysql> delimiter //
mysql>CREATE TRIGGER supply_and_demand
-> AFTER INSERT ON order_lines
-> FOR EACH ROW
-> BEGIN
-> DECLARE price_increase DECIMAL(7,2);
-> SELECT ROUND(price * 0.01 * NEW.quantity, 2)
-> INTO price_increase
-> FROM products
-> WHERE product_code = NEW.product_code;
->
-> UPDATE products
-> SET price = price + price_increase
-> WHERE product_code = NEW.product_code;
->
-> UPDATE products
-> SET price = GREATEST (1.00, price - price_increase)
-> WHERE product_code = (
-> SELECT product_code
-> FROM order_lines
-> WHERE product_code(=)NEW.product_code
-> GROUP BY product_code
-> ORDER BY SUM (quantity)
-> LIMIT 1
-> );
->
-> END
-> //
Query OK, 0 rows affected (0.00 sec)
Let's take this trigger a step at a time. The trigger is set to fire AFTER INSERT on the order_lines
tablethis is the table that contains details on how many of each product form part of an order.
The first line of the trigger code declares a local variable named price_increase that will be used to
store the amount by which the product sold will be increased and the least popular product will be
decreased.
The value of price_increase is calculated from the price of the product that has been sold and the
quantity in this order. Note that the NEW pseudotable contains only the columns from order_linesthe
table that causes the trigger to fire when an INSERT is performedso you have to query the products
table using NEW.product_code to find that product's price.
The next step performs a straightforward update on the products table, increasing the price for
NEW.product by price_increase.
Finally, the price of the least popular product is decreased using the following statement:
UPDATE products
SET price = GREATEST(1.00, price - price_increase)
WHERE product_code = (
SELECT product_code
FROM order_lines
WHERE product_code(=)NEW.product_code
GROUP BY product_code
ORDER BY SUM(quantity)
LIMIT 1
);
The GREATEST function ensures that the lowest a price can go when decreased is $1. The price value
is set for the product_code returned by the subquery. Grouping by product_code and ordering by
SUM (quantity )the total number of units ordered for each productthe subquery will return products
with those that have the fewest number of orders first.
The output from the following query shows the popularity of the products based on the initial values
in order_lines from the sample database:
The following query shows the initial products and their prices from the sample database:
When the products table is queried, you can see that the prices have been adjusted accordingly:
+--------------+----------------+--------+-------+
| product_code | name | weight | price |
+--------------+----------------+--------+-------+
| MINI | Small product | 1.50 | 4.99 |
| MIDI | Medium product | 4.50 | 10.99 |
| MAXI | Large product | 8.00 | 15.99 |
+--------------+----------------+--------+-------+
3 rows in set (0.00 sec)
The price of the product ordered (MIDI) has gone up by $1. One percent of its original value is
$0.10, and the quantity ordered is 10. The MINI product has been decreased in price by the same
$1.
A lot of output is produced because the output also contains the entire trigger body code. To view
only the triggers for a particular table, use SHOW TRIGGERS LIKE 'table_name'.
Dropping Triggers
A trigger remains always active while it exists in the database. To remove a trigger, you must use
the DROP TRIGGER command along with the name you gave to the trigger when you created it.
Disabling Triggers
If you want to disable a trigger but think you might need to reactivate
it later, you still have to drop the trigger from the database. Be sure
to take a copy of the CREATE TRIGGER statement from the output of
SHOW TRIGGERS first.
Although this means that all triggers are created and owned by a MySQL superuser, a user who
issues a SQL statement that causes a trigger to fire still requires sufficient privileges to execute the
trigger code.
Summary
In this lesson, you learned how to use database triggers in MySQL. In the next part of this book,
you will learn how to interface with a MySQL database using various programming languages.
Part 6: Interfacing with MySQL
Lesson 22. Using ODBC
You can also use ODBC to connect a database server to a client where there is otherwise no support
available. So if MySQL does not include a specific API, you can still use it as your database back end
through ODBC.
Obtaining MyODBC
The ODBC driver for MySQL is called Connector/ODBC and is available as a separate package,
downloadable from http://dev.mysql.com/downloads/. The current stable version is 3.51, which
implements the ODBC 3.51 specification.
MyODBC
Historically, the ODBC driver for MySQL was called MyODBC, so you
might see it called by this name. The new name is consistent with
other MySQL data drivers, including Connector/J for Java and
Connector/Net for .NET.
Connecting to MyODBC
To communicate with a database, you need to specify a data source, which is exactly what it saysa
source from which data can be fetched using an ODBC connection.
Each data source needs to be defined only once and is given a unique name known as a Data
Source Name, or DSN. The DSN contains the connection parameters that identify a MySQL server
and the user authentication required to log on.
The Data Source Administrator window appears. Figure 22.1 shows how this might look, although
on your system the actual data sources shown might be different.
Figure 22.3 shows the first tab of the Connector/ODBC configuration being completed.
The Server value can be an IP address or the hostname of the MySQL server you want to connect
to. Enter User and Password values that correspond to a valid user account on that MySQL server
when connecting from the current host.
Press the Test button to verify that your connection parameters are correct; if there are problems,
use the Diagnostics button to view the error messages. When you have a successful connection, the
Database menu will be populated with all the database names that the connected user can access.
You can then select the database you want to use for this data source.
Connection Port
If you need to set the TCP/IP port to a value other than the default
(3306), this option is in the Connect Options tab in the
Connector/ODBC configuration.
Press the OK button to save the new data source; you are returned to the Data Source
Administrator window. You can adjust the connection parameters from here by selecting the data
source name and pressing the Configure button.
[myodbc]
Driver = /usr/local/lib/libmyodbc.so
Description = MySQL on a remote server
SERVER = 192.168.1.202
PORT =
USER = mysql10
Password = abc1234
Database = mysql10
OPTION = 3
SOCKET =
You can specify multiple DSNs in this one file, giving each an entry in the [ODBC Data Sources]
section and then giving the configuration specified using the DSN as a section heading in brackets.
In this example, [myodbc] indicates the start of the connection parameters for that DSN.
In the Data menu, select Get External Data and then New Database Query, as shown in Figure 22.4.
The Choose Data Source window appears and contains the DSNs available on your system. Select a
MySQL data sourcein the examples shown, the DSN is named myodbc and connects to a database
named mysql10 that contains the sample tables used in this book (see Figure 22.5). Then press the
OK button.
Next you will see the Query Wizard. This enables you to select the columns to pull through into your
spreadsheet. As a simple example, simply select all the columns from the products table by
selecting products and pressing the > button. The result is shown in Figure 22.6.
Figure 22.6. Selecting columns in the Query Wizard.
The remaining steps of the wizard can be used to generate more complex queries based on your
MySQL data. You can select a filter condition and specify ordering, if desired. Behind the scenes, the
Query Wizard is building an SQL query that is about to be passed to MySQL to fetch the
corresponding data.
After the final step of the wizard, press the Finish button. You are asked to select a location in the
spreadsheet for the data to be insertedjust select the default location, which is the top-left cell,
assuming that you started with a blank worksheet. Figure 22.7 shows the result: an Excel
spreadsheet containing the contents of the products table.
The C Language API is the native programming interface for MySQL. In fact, virtually all the other
APIs that are available use the C API. For example, the PHP interface, which you will learn about in
Lesson 24, "Using MySQL with PHP," is written in C using this API. It contains many functions that
map directly to a corresponding function in the underlying C library.
Client Programs
The client utilities shipped with MySQL, such as mysql and mysqladmin,
are all written using the C API. You can examine the source code for
these if you want to see how they work.
Your programs must include the header file mysql.h, which is also installed automatically when
building from source. It installs to a subdirectory off your include pathusually
/usr/include/mysql/mysql.hso your program must contain this statement at the beginning.
#include <mysql/mysql.h>
Binary Installation
For example, the current version of the RPM package for Red Hat
Enterprise is named MySQL-devel-standard-5.0.18-0.rhel3.i386.rpm.
$ mysql_config --cflags
-I/usr/include/mysql -mcpu=i486 -fno-strength-reduce
$ mysql_config --include
-I/usr/include/mysql
$ mysql_config --libs
-L/usr/lib/mysql -lmysqlclient -lz -lcrypt -lnsl -lm -lc -lnss_files
-lnss_dns -lresolv -lc -lnss_files -lnss_dns -lresolv
A failsafe way to pass all the correct compiler options to GCC is to use a shell escape, like this:
Connecting to MySQL
The first MySQL API function you need to learn is how to connect to a MySQL database. This is
actually done in two stages.
Firstly, you must initialize a new instance of a data structure that will become your connection
reference for all future function calls using that database. The object must be declared as type
MYSQLnote the unusual capitalization hereand you initialize it for use by the API by passing it to the
mysql_init() function.
Next, you call the mysql_real_connect() function to initiate a connection to a MySQL database. Look
at the example in Listing 23.1 first; we'll look at each value that can be passed as an argument in
turn.
#include <stdio.h>
#include <mysql/mysql.h>
main() {
MYSQL mysql;
mysql_init(&mysql);
if (!mysql_real_connect(&mysql, "localhost",
"username", "password", "mysql10",
0, NULL, 0))
{
fprintf(stderr, "Unable to connect to MySQL server\n");
}
Of course, this program does not really do anything beyond establishing a connection to the
database and giving an error if the connection failed. For now, let this just serve as an example of
how to create a database connection using the C API.
The return value from mysql_real_connect() is a MYSQL type objectin fact, the same value as the
first argumentif the connection is successful, or NULL if it failed for any reason. We examine some
more detailed error-reporting functions later in this chapter.
The mysql_real_connect() function takes eight arguments, with the function prototype shown here:
1.
2.
1. mysqlThe MYSQL type object that you initialized previously with mysql_init().
2. hostThe hostname of the MySQL server. This can be an IP address, domain name or
hostname, or localhost for servers running on the same host as the client program.
6. portThe port number for TCP/IP connections. For localhost connections or to use the default
port, use 0 here.
7. unix_socketThe name of the socket or named pipe for local connections. For TCP/IP
connections or to use the default socket, use NULL here.
8. client_flagThis argument can be used to enable certain features of the client library that are
not covered in this book. Use 0 here unless you have a specific need.
Executing a Query
After you have established a connection to a MySQL server, you can issue a query to the database
using the mysql_query() function. The first argument to this function is a connection reference. The
second should be a null-terminated string that contains a single SQL query.
If the query you want to execute contains binary data, use mysql_real_query() instead. This
function takes three arguments, with the third being the length of the query string. Using this
function, any instances of the \0 character in your data are not treated as the null terminator in the
string.
Terminating Queries
The return value from mysql_query() or mysql_real_query() is NULL to indicate success. If MySQL
encounters an error, the function returns one of the values shown in Table 23.1.
If the return value is not NULL, you can call the mysql_errno() and mysql_error() messages to
display the MySQL error number and message text, respectively. They each take a single argument,
which is the connection handle.
To create a result handle, call the mysql_use_result() function. It takes a single argumenta
database connection handleand returns a result object that corresponds to the most recently
executed query on that connection.
The return value from mysql_use_result() is either NULL to indicate success or one of the error
values from Table 23.1. When a result handle has been successfully assigned, you can continue to
execute other queries using the same database connection.
The most powerful way to fetch data from a result handle is with the mysql_fetch_row() function.
The first time you call mysql_fetch_row(), the first row from the data set is returned and each
subsequent call returns the next row until no data remains to be fetched.
The data is returned into a MYSQL_ROW type structure, which contains one element for each column
returned by the query. The elements are numbered from zero, in the order they appear in the
SELECT statement.
For example, suppose that your program executes the query SELECT code, price FROM products
ORDER BY price and then uses mysql_fetch_row() to return the first row into a structure named
result. The value contained in result[0] will be the code for the first product returnedwith this
query, the least expensive product in the tableand result[1] will hold its price value.
The mysql_num_fields() function tells you the number of columns the query returns. Using this in a
loop, you can fetch a value from each column. The example in Listing 23.2 uses this technique,
along with the other functions you have learned so far in this chapter, to produce a complete query
example using the C API.
Counting Rows Returned
#include <stdio.h>
#include <mysql/mysql.h>
main() {
MYSQL mysql;
MYSQL_RES *result;
MYSQL_ROW row;
int numrows, numcols, c;
mysql_init(&mysql);
if (!mysql_real_connect(&mysql, "localhost",
"username", "password", "mysql10",
0, NULL, 0))
{
fprintf(stderr, "Error connecting: Error %d: %s\n",
mysql_errno(&mysql), mysql_error(&mysql));
}
/* Execute a query */
if (mysql_query(&mysql, query))
{
fprintf(stderr, "Error executing query: Error %d: %s\n",
mysql_errno(&mysql), mysql_error(&mysql));
}
result = mysql_use_result(&mysql);
if (!result)
{
fprintf(stderr, "Error using result: Error %d: %s\n",
mysql_errno(&mysql), mysql_error(&mysql));
}
numcols = mysql_num_fields(result);
Using a Result
The function mysql_affected_rows() can be used to determine the effect of an INSERT, UPDATE, or
DELETE statement. It returns the number of rows affected by the SQL statement.
For INSERT and DELETE statements, this is a straight count of the number of rows added or removed
by the operation. When the statement performed is an UPDATE, the return value from
mysql_affected_rows() is the number of rows in which a value was changed from its previous value;
this could be less than the total number of rows matched in the WHERE clause.
Tidying Up
To keep your program efficient, make sure you free up any resources that are no longer required.
Use mysql_free_result() to deallocate the resources associated with a result handle. After you have
freed the result resource, you should not attempt to access it again in the program. This function
takes a single argument, which is a MYSQL_RES type of object.
When you are done with the database connection altogether, use mysql_close() with a database
handle as its argument to close the connection and free up the resource.
Summary
In this lesson, you learned how to communicate with a MySQL database from a program using the C
API. In the next lesson, you will learn how to use the PHP API to create database-driven web pages.
Lesson 24. Using MySQL with PHP
In this lesson, you learn how to communicate with a MySQL database from a PHP script.
PHP actually has two different APIs for MySQL, both of which are covered in this chapter. The first,
mysql, is the classic set of functions that are available in all versions of PHP.
The new interface is mysqli, which stands for MySQL Improved. It is available only in PHP version 5
and works only with MySQL version 4.1 and higher. The mysqli interface can be used through a set
of functions or in an object-oriented manner, to fit the improved OO capabilities of PHP 5.
Using the mysql API
The classic mysql interface for PHP is a set of functions that map very closely to the C API functions
you learned about in Lesson 23, "Using MySQL with C." To check whether this module is included in
your PHP installation, create a simple script that simply contains the following line:
<?php phpinfo();?>
View this script in a web browser and look for a section headed MySQL Support . If this section is not
present, you will not be able to use the MySQL commands in PHP, and you will have to recompile
PHP to include this module.
Configuring PHP
Connecting to MySQL
Use the mysql_connect() function to establish a connection to a MySQL database. The first three
arguments are the server hostname, username, and password for the connection. The following
statement opens a new connection to a local MySQL server and assigns a connection handle named
$conn:
You must assign the connection handle resource returned by mysql_connect() so that you can use it
later. Most MySQL API functions require this to be passed as an argument.
1. serverThe hostname of the MySQL server. This can be an IP address, domain name or
2.
1.
hostname, or localhost where the MySQL server and web server are running on the same
host.
4. new_link Pass a nonzero value in this argument to cause a second call to mysql_connect() to
create a separate database link. Otherwise, any existing connection will be reused.
5. client_flagsThis argument can be used to enable certain features of the client library that are
not covered in this book. Omit this argument unless you have a specific need.
Server Port
The return value from mysql_connect() is FALSE if the connection fails for any reason. You can then
use the mysql_errno() and mysql_error() functions to return the MySQL error number and message
text, respectively.
The argument to both error functions is a database connection handle, but the argument can be
omitted if there is only one open connection in your script. The default behavior is to use the most
recently opened connection.
The connection to the database server is made without selecting a database to work with. This must
be done using a separate function, mysql_select_db(). The first argument is the name of the
database to use. You can pass a connection handle as an optional second argument or omit this
argument to use the most recently opened connection.
The following statement causes any queries executed using the $conn connection handle to use the
mysql10 database:
mysql_select_db("mysql10", $conn);
Authentication
Listing 24.1 performs both steps, connecting to a MySQL server and selecting a database to use,
with error checking along the way.
<?php
exit;
}
if (!mysql_select_db("mysql10")) {
echo "Unable to select database <>";
echo "Error " . mysql_errno() . " - " . mysql_error();
exit;
}
?>
Executing a Query
After you have established a connection to a MySQL server, you can execute a query using the
mysql_query() function. This function takes two arguments: a database connection handle and a
string containing a single SQL query. The terminating semicolon is not required. The following is an
example using a database resource named $conn:
$result = mysql_query($conn, "SELECT * FROM products");
The return value from mysql_query() is a result handle that you then use to find information about
the query and fetch records if the query was a SELECT statement.
The result is FALSE if the query failed for any reason; you can then use mysql_errno() and
mysql_error() to find out more information.
The mysql_num_fields() function works in a similar manner and tells you the number of columns in
the data set.
If the query you executed was an UPDATE, INSERT, or DELETE statement, you can find out how many
table rows were affected using the mysql_affected_rows() function. It also takes a result handle
argument and returns the number of rows that were affected by the query.
Affected Rows
The data is returned into an array that, by default, has both numeric and associative indexes. The
elements are numbered from zero in the order they appear in the SELECT statement. They also have
textual keys that correspond to the column name or alias from the query.
For example, suppose your script executes the query SELECT code, price FROM products ORDER BY
price and then uses mysql_fetch_row() to return the first data row into $result. The value of
$result[0] would be the code for the first product returned, and $result[1] would hold the
corresponding price value. However, these values could also be accessed as $result["code"] and
$result["price"].
Listing 24.2 puts everything together into a script that connects to MySQL, executes a query, and
fetches and displays the resulting data.
<?php
if (!mysql_select_db("mysql10")) {
echo "Unable to select database <>";
echo "Error " . mysql_errno() . " - " . mysql_error();
exit;
}
$numrows = mysql_num_rows($result);
$numcols = mysql_num_fields($result);
The output from this script is in an HTML table format. Each time a new record is fetched, the script
outputs a <tr> tag and closes it with </tr> at the end of the loop. Each individual data item is
enclosed in <td> and </td>. Running this script produces output similar to that shown in Figure
24.1.
Tidying Up
When your script has finished running, any associated resources are automatically deallocated.
However you might want to do some housekeeping in your script to free up resources that you are
done with.
The mysql_free_result() function destroys a result handle and deallocates its resources. You then
cannot use that result handle with any of the mysql API functions.
The function mysql_close() takes a database handle argument. It disconnects from the MySQL
server immediately and frees up the associated resources.
Using the mysqli API
To check whether your version of PHP includes mysqli support, run the phpinfo() command and
look for a section headed MySQLi Support.
MySQLi Support
The MySQLi API can be used both procedurally and in an object-oriented manner. The procedural
interface is very similar to the classic mysql APIfor instance, it uses functions such as
mysqli_query() and mysqli_fetch_row() . Therefore, in this section, you learn how to use MySQLi
with objects.
Connecting to MySQL
The constructor function for a mysqli class object is used to initialize a MySQL connection. The
following statement creates a new object with a connection to a database on the local host:
0. hostThe hostname of the MySQL server. This can be an IP address, domain name or
hostname, or localhost where the MySQL server and web server are running on the same
host.
3. dbnameThe database name to connect to. Unlike in the mysql API, you do not need to make a
separate function call to select the database.
4.
2.
3.
4. portThe port number for TCP/IP connections. For localhost connections or to use the default
port, omit this argument or pass NULL.
5. socketThe name of the socket or named pipe for local connections. For TCP/IP connections or
to use the default socket, omit this argument or pass NULL.
If the connection fails, call the mysqli_connect_errno() and mysqli_connect_error() functions to find
the MySQL error number and message text, respectively. Because the constructor function failed,
you cannot call these functions as methods on a mysqli object.
Listing 24.3 creates a new mysqli database connection with error trapping.
<?php
?>
Executing a Query
When you have a mysqli object that is connected to a MySQL server, you can execute a query using
the query() method. Its argument is a string that contains a single SQL query; the terminating
semicolon is not required. The following statement is an example:
If the query is successful, a result object is returned that then is used to find information about the
query and to retrieve data rows if the query was a SELECT statement.
Otherwise, the return value is FALSE. You can check the errno and error properties on the
connection object to find the MySQL error number and message text, respectively.
Object Properties
The field_count property similarly contains the number of columns in the data set. The
affected_rows property contains the number of rows affected by an UPDATE, INSERT, or DELETE
statement.
The data is returned into an object that contains a property for each column in the data set. The
property's name is the same as the selected column name or alias in the query.
For example, suppose that your script executes the query SELECT code, price FROM products ORDER
BY price and then uses fetch_object() to return the first data row into $data. The value of $data-
>code would be the code for the first product returnedwith this query, the least expensive product in
the tableand $data->price would hold the corresponding price value.
The fetch_row() method works in the same way, except that it creates an array structure rather
than an object, with each element indexed both numerically and associatively. Using the same
example query, $data[0] and $data["code"] would both contain the product code.
Listing 24.4 puts everything together into a script that connects to MySQL, executes a query, and
fetches and displays the resulting data.
<?php
$conn = new mysqli("localhost", "user", "pass", "mysql10");
if (mysqli_connect_errno()) {
echo "Unable to connect to MySQL server <>";
echo "Error " . mysqli_connect_errno() . " - " . mysqli_connect_error();
exit;
}
if (!$result) {
echo "Unable to execute query <>";
echo "Error " . $result->errno . " - " . $result->error;
exit;
}
?>
This script uses the fetch_row() method to retrieve data because the output is generated in a loop.
In many cases, you will know the column names for the data you are working with, and the
fetch_object() method might be more convenient.
MySQL vs. MySQLi
If you are familiar with another PHP database API, you will be familiar
with the way the classic MySQL interface works. To see how the
object-oriented MySQLi API compares, run through Listing 24.2 and
Listing 24.4 step by stepthey give exactly the same result.
Tidying Up
To deallocate a resource object, call the $result->free() method. Doing so destroys the object, so
you no longer can call its methods or view its properties.
To disconnect from the database, call $conn->close(). The database connection is closed
immediately and the connection object is destroyed.
Summary
In this lesson, you learned how to communicate with a MySQL server from a PHP script using both
the available APIs. In the next lesson, you will learn how to use the Perl Database Interface with
PHP.
Lesson 25. Using MySQL with Perl
In this lesson, you learn how to communicate with a MySQL database from a Perl script.
The Perl DBI
MySQL connectivity from Perl is handled in the same way that you can communicate with many
other types of database: using the Perl Database Interface, or DBI.
If you have already used DBI with another database, you already know the essentials and will find it
very easy to interface with MySQL.
DBI is independent of the database back ends and uses a specific database driver module, known as
DBD, to interface with each DBMS.
If you do not already have DBI installed, use cpan to download and install it, as follows. You should
either run this command as the root user on your system or have your system administrator run it
for you.
# cpan
cpan> install DBI
The installation process produces a lot of output as it downloads and installs DBI and any other
modules that it is dependent upon.
CPAN
You also need to install a database driver for MySQL, which is called DBD::mysql. Enter this
command at the cpan> prompt:
On Windows systems using the ActivePerl distribution, use the ppm.bat script to install Perl modules,
as follows:
C:\perl\bin> ppm.bat
ppm> install DBI
...
ppm> install dbd::mysql
Using the MySQL DBD
Any Perl script that uses DBI with the MySQL DBD module should begin with the following line:
use Mysql;
Mysql
Note the unusual capitalization of Mysql that is used in the Perl API.
The name of this extension is case sensitive.
Connecting to MySQL
You establish a connection to a MySQL database by calling the connect() method on the master
Mysql object. The following statement opens a new connection to the database mysql10 on a local
MySQL server and assigns a database handle named $dbh.
hostThe hostname of the MySQL server. This can be an IP address, domain name, or
hostname. Use undef when the database server is localhost.
The return value when a successful connection has been made is a database handle resource. If an
error arises when connecting to the database, the properties errno and errstr on the master Mysql
object will contain the MySQL error number of message text, respectively.
You can use a statement such as the following to perform a database connection with error
trapping:
Executing a Query
When you have a database handle resource that is connected to a MySQL server, you can execute a
query using the query() method on the database handle. Its argument should be a single SQL
statement; the terminating semicolon is not required. The following statement is an example:
The return value is a statement handle, which was assigned to $sth in this example. The statement
handle is used to find information about the query and to retrieve data rows.
If an error occurs while executing the query, you can access the errno and errstr properties on the
database handle object to retrieve the MySQL error number and message text, respectively.
You can use the following statement to execute a query and display the associated error message if
there is a problem:
The num_fields property similarly contains the number of columns in the data set. The
affected_rows property contains the number of rows affected by an UPDATE, INSERT, or DELETE
statement.
The first time you call fetchrow(), the first row from the data set is returned; subsequent calls
return the next row until there is no data left to be fetched.
The array elements are numbered from zero in the order they appear in the SELECT statement. For
example, suppose that your script executes the query SELECT code, price FROM products ORDER BY
price and then uses $sth->fetchrow to return a row of data into @data. The value in $data[0] will be
the code for the first product returned, and $data[1] will be its price.
To reference data by its column name or alias, use the fetchrow_hash method. Using the previous
example query and fetchrow_hash , you would be able to reference the values selected as $data-
>{code} and $data->{price}.
Listing 25.1 puts everything together into a script that connects to MySQL, executes a query, and
fetches and displays the resulting data.
#!/usr/bin/perl
use Mysql;
Running this script produces the output shown here: the contents of the customers table in
tabulated format.
$ perl listing25.1.pl
MUSGRP Musicians of America
PRESINC Presidents Incorporated
SCICORP Science Corporation
Tidying Up
Database connections opened in your script are automatically closed and resources are deallocated
when the script ends. There is no specific function to explicitly disconnect from a database in the
Perl DBI.
However, to free up any resources allocated in a running script, you can simply use undef to free
the handle.
Summary
In this lesson, you learned how to use the Perl DBI with the MySQL DBD to communicate with a
MySQL database from a Perl script. The last section of this book contains a number of appendixes
for your reference.
Part 7: Appendix
Appendix A. Installing MySQL
At the time of this writing, this page shows that the recommended current release is MySQL 5.0,
with alpha releases of MySQL 5.1 also available. If you click through to download MySQL 5.0, you
are taken to http://dev.mysql.com/downloads/mysql/5.0.html.
This page lists the MySQL downloads by platform, with a link to download each. The latest version
number and the file size are displayed alongside each package.
The following sections explain which packages you require for each type of installation.
Linux/UNIX Installation
Follow these steps to install MySQL on a Linux/UNIX server. You must be logged in as the root user
to install MySQL.
The RPM distribution is split into the following packages. The filename prefix for each package is
shown in parentheses.
Server (MySQL-server)The MySQL database server. You must install this package.
Libraries and header files (MySQL-devel)Development libraries and header files required for
creating statically linked programs with the C API.
Dynamic client libraries (MySQL-shared)Shared libraries required for creating and running
dynamically linked client programs.
The full filename of a package consists of the prefix shown in this list, the MySQL version number,
and the platform it is compiled for.
For example, the latest version of the MySQL Server package for an Intel-based Linux system is
installed from an RPM package named MySQL-server-5.0.18-0.i386.rpm.
Use the rpm command with the i switch to install the RPM packages. If you have downloaded several
packages, you can install them together by using the following command:
$ rpm i MySQL*.rpm
RPM Versions
Specific sets of RPM packages exist for Red Hat Enterprise Linux and
SUSE Enterprise Linux. If you use one of these enterprise platforms,
you must obtain the correct RPM versions.
RPM installation creates a service for MySQL. You can start the MySQL server by issuing the
following command:
Binary Installation
If you are unable to use RPM, you will still likely find a precompiled binary version of MySQL
available for your system.
Binary Distribution
The binary distribution of MySQL is a single compressed archive that contains the server, client
programs, and development libraries. It is downloadable in a .tar.gz filearchived using tar and
compressed using gzip. Three versions of each binary distribution exist: Standard, Max, and Debug.
The Standard binaries are fine for most usersthis is an optimized MySQL server with all the
common features enabled at compile time.
The Max binaries include additional features that are new or are not yet considered fully
stable. You should consider using the Max distribution only if you have a specific need for it.
The Debug binaries have additional debugging information compiled and are not suitable for
general use. You should not use this distribution.
The binary download filename consists of mysql-standard (or mysql-max, for Max) followed by the
version number and the platform. For example, if you are installing MySQL on an Intel-based
OpenBSD system, the package you require will be named mysql-standard-5.0.16-openbsd3.7-i386.
After downloading the appropriate file, extract it using the following command. Use the cd command
to navigate to the location where you want to install the files first: /usr/mysql and /usr/local/mysql
are typical locations.
Paths
To start the MySQL server, run the mysqld_safe program, which will have been installed to the bin
directory. You should run this program in the background as follows:
# /usr/local/mysql/bin/mysqld_safe &
The source code downloads appear at the very bottom of the downloads page. They are available as
a .tar.gz file; the filename simply contains the version number.
Begin by extracting the latest version of the MySQL source to a suitable location, such as
/usr/local/src.
Next, run the configure program to allow the MySQL installation process to gather information about
your system.
Compile-Time Configuration
# ./configure
The configure program generates a Makefile , so now you can run the make command to compile the
MySQL server and client programs and the development libraries.
# make
Compiling MySQL might take some time, but when it is complete, you can install the various
components to their correct locations by issuing a make install command.
Install Locations
First, download the latest version of the installer. The filename of the latest version at the time of
this writing is mysql-essetials-5.0.18-win32.msi. Save this file to your desktop.
Double-click the installer icon to initiate the Setup Wizard. Click the Next button to advance to a
screen like the one shown in Figure A.1.
Unless you have a specific reason to customize the installation, the default selection of Typical is
fine. Click Next to continue.
The next screen confirms the location to which MySQL will be installed. Click the Install button to
begin installation. It might take a few minutes for the MySQL installer to copy files.
The next window asks you to sign up for a MySQL.com account if you do not already have one. If
you already have an account, enter your email address and password in the boxes. You can select
Skip Sign-Up to skip this step, if you want. Click Next to continue.
Installation is now complete. You will see a window like the one shown in Figure A.2.
Click the Finish button to begin configuring the MySQL Server and launch the Configuration Wizard.
Click Next; you will see the configuration type selection shown in Figure A.3.
The window shown in Figure A.4 enables you to install MySQL as a Windows service. This option is
checked by default, and it's the easiest way to get the MySQL server running.
The next window, shown in Figure A.5, requires you to set a new password for the root user.
Do not select the check box to enable root access from remote
machines unless you are sure that you want to do this. Remember,
you can always grant more privileges later. Even if you do want to
allow remote superuser access, you should think about restricting it
to certain IP addresses only. Refer to Lesson 18, "Managing User
Access," for more information.
Enter a new password and confirm it by entering it a second time. Then click Next. The
Configuration Wizard is ready to perform the configuration. Click the Execute button to continue.
MySQL installation is now complete. You will find a new program group called MySQL on your start
menu; it contains a link to the configuration wizard in case you need to change any of the settings.
There is also a link to the mysql command-line monitor.
To start and stop the MySQL service, select Control Panel, then Administrative Tools, and then
Services. You can start, stop, pause, and restart the service from the Services manager.
Appendix B. Sample Table Scripts
As you follow each lesson in this book, you are strongly encouraged to try out each example on your
own MySQL server.
The tables used by the examples throughout the book are created using the following SQL script.
The script contains CREATE TABLE statements that define each table and some INSERT statements to
populate the tables with their initial values.
Sample Database
You can download the SQL file printed here from the Sams Publishing
website at http://www.samspublishing.com.
* (multiplication) operator
+ (addition) operator
- (subtraction) operator
/ (division) operator
Index
[SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W]
data
autocommit mode
DELETE command
filtering on exact values
filtering on range of values
grouping
indexes
compound
CREATE INDEX command
defining key columns
dropping
foreign key constraints with InnoDB
full-text
partial
viewing on table
INSERT command
default column values
inserting row using query
multiple rows
keys
loading from file
maintenance trigger
REPLACE command
summarizing with aggregate functions
AVG( )
COUNT( )
MAX( )
MIN( )
SUM( )
transactions, MySQL
UPDATE command
Data Definition Language
databases
altering
character sets
collations
creating
dropping
tables
altering
autoincrementing column
creating
default values
dropping
storage engines
temporary
using queries to create
Data Manipulation Language
autocommit mode
DELETE command
INSERT command
default column values
inserting row using query
multiple rows
loading from file
REPLACE command
transactions
MySQL
reasons for using
rolling back
UPDATE command
Data Source Administrator window
Data Source Name (DSN)
data sources
data types
database design
binary large object
character
date
decimal
integer
text
time
variable character
tables
Database Interface (DBI), Perl
database level routines
database switch, mysql client program
database-management system (DBMS)
databases
altering
anatomy
character sets
collations
creating
designing
data types
naming tables and columns
normalization
relationships
dropping
lists, retrieving (SELECT statement)
MySQL
capturing output (mysql client program)
commands, editing (mysql client program)
connecting (mysql client program)
connection status, viewing (mysql client program)
exiting (mysql client program)
query output formats (mysql client program)
selecting (mysql client program)
SQL command entry (mysql client program)
zero record retrieval (mysql client program)
reasons for using MySQL
records, order of
referential integrity
relational
SQL (Structured Query Language)
tables
altering
autoincrementing column
creating
default values
dropping
storage engines
temporary
using queries to create
DATE data types
DATE FORMAT( ) function, format characters
date functions, complete listing of (MySQL.com)
date operators, representational formats
DATEDIFF( ) function, date difference computations
dates
arithmetic operators
data types
formatting (DATE FORMAT( ) function)
functions
CONVERT TZ( )
CURDATE( )
DATE FORMAT( )
DATEDIFF( )
EXTRACT( )
NOW( )
TIMEDIFF( )
UTC DATE( )
UTC TIME( )
UTC TIMESTAMP( )
representational formats
storing values in columns
validation
DATETIME data types
DBD module, Perl
connecting to MySQL
executing a query
fetching query data
finding query information
resource cleanup
DBI (Database Interface), Perl
DBMS (database-management system)
dbname argument
Debug binaries
DECIMAL data type
decimals, data types
DECLARE command
DEFAULT keyword, tables
default values, tables
DEGREES( ) function
DELETE command, data manipulation
DELETE privilege
DELETE trigger
delimiters
character
strings
descending sort orders (DESC keyword)
DESCRIBE command 2nd
designing databases
data types
binary large object
character
date
decimal
integer
text
time
variable character
naming tables and columns
normalization
relationships
Developer Zone
DISTINCT keyword
division (/) operator
downloads
MySQL installation
ODBC (Open Database Connectivity)
drivers, data source selection
DROP DATABASE command
DROP INDEX command
DROP keyword, altering tables
DROP privilege
DROP TABLE command
DROP TABLE IF EXISTS command
DROP TRIGGER command
DROP USER command
DROP VIEW command
dropping
databases
indexes
primary keys
stored routines
tables
triggers
views
DSN (Data Source Name)
duplicated indexes
dynamic client libraries, Linux/UNIX server installation
Index
[SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W]
IF( ) function
IFNULL( ) function
IN operator, WHERE clause
INDEX privilege
indexes [See also keys.]
compound
CREATE INDEX command
defining key columns
dropping
duplicate
foreign key constraints with InnoDB
full-text
partial
viewing on table
INNER JOIN keyword, SELECT statement
inner joins 2nd
InnoDB, foreign key constraints
INSERT command
alternative syntax
data manipulation
default column values
insert row using query
multiple rows
INSERT privilege
INSERT statements
tables
installation
binary
default locations
downloading MySQL
Linux/UNIX server
binary version
RPM packages
source code
sample tables
Windows
INT data type
INTEGER data type
integer data types
INTERSECT operators
combined queries
simulating in temporary tables
INTERVAL operator, date/time arithmetic
INTO keyword, INSERT statements
Index
[SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W]
manuals, online
many-to-many relationships, tables
mathematical number functions
LOG( )
POW( )
SQRT( )
Max binaries
MAX( ) function, data aggregation
MEDIUMBLOB data type
MEDIUMINT data type
MEDIUMTEXT data type
MEMORY storage engine
MERGE algorithm
MIN( ) function, data aggregation
MINUS operators
combined queries
simulating in temporary tables
MOD operator
MODIFY keyword, altering tables
multiple errors, SELECT statement
multiple rows, INSERT command
multiplication (*) operator
multiuser access-control systems, authentication
MySQL
privilege tables
privileges
MyISAM storage engine, full-text indexes
MyODBC
data source creation
Excel example connection
UNIX/Linux data source
MySQL
components
downloading
reasons for using
resources
source code
user case studies
website 2nd
MySQL AB
MySQL Administrator's Guide
mysql argument
MySQL Certification Study Guide
mysql client
command-line client
MySQL databases
capturing output
connecting
editing commands
exiting
query output formats
selecting
SQL command entry
viewing connection status
zero record retrieval
mysql client program
\c command (clearing current command)
\e command (open editor)
\g command (query execution)
\r command (reconnection to databases)
\s command (show connection status)
\T command (query output)
database switch
host switch
password switch
user switch
MySQL databases
commands, editing (mysql client program)
connecting (mysql client program)
connection status, viewing (mysql client program)
exiting (mysql client program)
output, capturing (mysql client program)
query output formats (mysql client program)
selecting (mysql client program)
SQL commands, entry of (mysql client program)
SQL statements, executing (mysql client program)
zero record retrieval (mysql client program)
mysql interface, PHP scripts
connecting to MySQL
finding query information
gathering query data
query execution
resource cleanup
MySQL Language Reference
MySQL Server Instance Configuration wizard
MySQL Setup wizard
MySQL Tutorial
MySQL-bench package
MySQL-client package
MySQL-devel package
MySQL-server package
MySQL-shared package
MySQL.com
date functions listing
numeric functions listing
string functions listing
mysql_config utility
mysql_connect( ) function
mysql_fetch_row( ) function
mysql_free_result( ) function
mysql_num_rows( ) function
mysql_query( )
mysql_query( ) function
MySQLi API, PHP scripts
connecting to MySQL
fetching query data
finding query information
freeing up resources
query execution
Index
[SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W]
names, tables
NATURAL JOIN keyword, SELECT statement
natural joins
negating, conditions in queries
normalization, database relationships
NOT IN operators
NOT NULL constraint, tables
NOT operator, WHERE clause
NOW( ) function
NULL constraint, tables
NULL values
numeric operators
strings
null values, columns
NULLIF( ) function
numbers, conversion from string values
numeric functions
complete listing of (MySQL.com)
mathematical
random numbers
rounding numbers
CEILING( )
FLOOR( )
ROUND( )
TRUNCATE( )
trigonometric
ACOS( )
ASIN( )
ATAN( )
COS( )
DEGREES( )
RADIANS( )
SIN( )
TAN( )
numeric operators
arithmetic
calculated columns
NULL values
Index
[SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W]
padding functions
partial indexes
passwd argument
password switch, mysql client program
PASSWORD( ) function
passwords
assigning
setting
paths
binary installation
MySQL bin directory
Perl
DBD module
connecting to MySQL
executing a query
fetching query data
finding query information
resource cleanup
DBI (Database Interface)
PHP script
APIs
mysql interface
MySQLi API
configuring
ports
argument
connection
server connection
POW( ) function
precedence operators, WHERE clause (SELECT statement)
PRIMARY KEY field, tables
primary keys
compound
dropping
tables
privileges
changing
granting
passing on
revoking
stored routines
triggers
user access
views
wildcards
procedures
showing
stored, creating
PROCESS privilege
Index
[SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W]
queries
C Language API
executing
using results
combined
INTERSECT operator
MINUS operator
sorting on UNION operator
temporary tables
UNION ALL operator
UNION operator
conditions, negating
creating tables
data results
grouping (column aliases)
grouping (GROUP BY clause)
data summarization
AVG( ) function
COUNT( ) function
MAX( ) function
MIN( ) function
SUM( ) function
filtering by queries
formatting
limiting rows returned (LIMIT clause)
MySQL databases, output formats (mysql client program)
MySQLi API
Perl DBD module
executing
fetching data
finding information
PHP MySQL connection
shuffling (RAND( ) function)
skipping rows returned (LIMIT clause)
summary data, filtering (HAVING clause)
table joins 2nd
terminating 2nd
query( ) method
quotes, use around data values
Index
[SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W]
validation, dates
values, quotes usage
variable character data types
variables, stored functions
viewing MySQL databases, connection status (mysql client program)
views
algorithms
altering
cascading
creating
dropping
finding underlying query text
naming
privileges
showing
tables
updating
Index
[SYMBOL] [A] [B] [C] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W]
Web access
websites, MySQL 2nd
date functions listing
numeric functions listing
Sams Publishing
string functions listing
WHERE clause 2nd
AND operator
BETWEEN operator
filtering on an exact data value
filtering on multiple values
filtering on range of data values
IN operator
NOT operator
operator precedence
OR operator
quotes around values
wildcards
granting privileges
deleting users
viewing
usernames
Windows
MySQL components
MySQL installation
Windows Essentials, MySQL installation
WITH GRANT OPTION command