Welcome to my set of tutorials on MySQL. While
there are loads of tutorials on MySQL (usually in combination with a
scripting language) on the Net aimed at building applications etc
Part 3 - Manipulating Data
UPDATEs, DELETEs and Advanced SELECTs.
Introduction
In the previous part we have
looked at logging into MySQL, creating tables, adding and selecting data using
SQL statements. In this Workshop we will continue to look at other SQL commands,
specifically updating and deleting, and revisit the SELECT command to examine
different operators and options.
UPDATE-ing Records
The UPDATE SQL statement is similar to the SELECT statement as there must
be a WHERE condition to specify which record(s) to change.
UPDATE <table_name>
SET <column_name> = 'new_value'
WHERE (<column_name> = 'some_value');
So to change the 'title' in the first row of our 'cds' table from:
| 1 | jamiroquai | A Funk Odyssey | 2001 | Sony Soho2 | 2001-09-01 |
to:
| 1 | jamiroquai | Wrong Title | 2001 | Sony Soho2 | 2001-09-01 |
We would use the following statement:
mysql> UPDATE cds
-> SET cds.title = 'Wrong Title'
-> WHERE (cds.cdID = '1');
Query OK, 1 row affected (0.06 sec)
Rows matched: 1 Changed: 1 Warnings: 0
The value '1' in the 'cdID' column is the unique identifier
that allows us to change values. You can issue a SELECT statement if you want
to check the changes.
mysql> SELECT * FROM cds;
+------+------------+----------------+------+------------+------------+
| cdID | artist | title | year | label | bought |
+------+------------+----------------+------+------------+------------+
| 1 | jamiroquai | Wrong Title | 2001 | Sony Soho2 | 2001-09-01 |
| 2 | jamiroquai | A Funk Odyssey | 2001 | Sony Soho2 | 2001-09-01 |
We could also change multiple columns using one statement
mysql> UPDATE cds SET cds.title = 'Other Title',
-> cds.artist = 'artist'
-> WHERE (cds.cdID = '1');
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
The DELETE statement
By using the UPDATE statement we have altered the 'cds' table so that
there are no longer duplicate records in rows 1 and 2. However
we do have an incorrect record in row 1 and need to DELETE it. The
syntax for deleting rows is:
DELETE FROM <table_name>
WHERE (<column_name> = 'some_value');
Thus to remove our incorrect record
mysql> DELETE FROM cds
-> WHERE (cds.cdID = '1');
Query OK, 1 row affected (0.00 sec)
NOTE: When a record is deleted all the fields are deleted
INCLUDING the unique identifier, and the database does not renumber this auto_increment
COLUMN. So it is important to remember that the ID is not the same as the
row number, e.g. in our example row 2 has a cdID of 3, row 3 - cdID of 4 etc.
SELECT Revisited
In the first MySQL Virtual Workshop we looked at using the SELECT SQL statement
to retrieve data from a table. This was fairly limited in scope as we could
only retrieve data which matched a specific text string. In this section we
will look at retrieving data based on other criteria.
The first of these we will look at is Selecting a Number Range. We
have created two numeric COLUMNs in our 'cds' TABLE: the 'cdID'
and 'Year' COLUMNs. As each 'cdID' entry is unique, we will use the
'Year' COLUMN in the following examples. It is also important to note that
while we may recognise an entry in the 'Year' COLUMN as an actual year MySQL
only recognises it as a number.
Simple stuff first to select all from one year
mysql> SELECT * FROM cds
-> WHERE (cds.year = 2001);
Note that as the 'year' COLUMN is numeric rather than a text string we do
not need to enclose our search term in apostrophes (although if we did it
would treat the number '2001' as a text string and find it anyway).
If we wanted to expand our search term to include other years (as well as
2001) we need to use numeric operators.
Numeric Operators
Numeric operators are used to compare two numbers under several conditions.
|
Operator
|
Condition
|
|
=
|
Equal to
|
|
<>
|
Not equal to
|
|
>
|
Greater than
|
|
<
|
Less than
|
|
>=
|
Greater than or equal to
|
|
<=
|
Less than or equal to
|
Thus to display all cds that were released before 2001:
mysql> SELECT * FROM cds
-> WHERE (cds.year < 2001);
Or all cds in / after 1990:
mysql> SELECT * FROM cds
-> WHERE (cds.year >= 1990);
So we are able to select records by a column's numeric content.
Other Operators
There are two other operators so far unmentioned, the LIKE and BETWEEN operators.
The LIKE operator is used when we want to match part of the data in a field
by using the '%' wildcard. So if we wanted to search the 'title' field
for all albums beginning with 'A' we would use the following statement.
mysql> SELECT * FROM cds
-> WHERE (cds.title LIKE 'A%');
The 'A' in the search string is followed by our wildcard character. To match
the word 'the' in any title we would put a wildcard character before and afterwards
in the SQL statement.
mysql> SELECT * FROM cds
-> WHERE (cds.title LIKE '%the%');
The BETWEEN statement is used to add more functionality to a condition, allowing
us to select a range of values from a column.
SELECT <column_name> FROM <table_name>
WHERE (<column_name> BETWEEN value1 AND value2)
Thus we could select a numeric range
mysql> SELECT * FROM cds
-> WHERE (cds.year BETWEEN 1995 AND 1998);
Or we could select an alphanumeric range. To select all artists alphabetically
between 'Elvis' and 'Michael Jackson'
mysql> SELECT * FROM cds
-> WHERE (cds.artist BETWEEN 'Elvis' AND 'Michael Jackson');
Which might return 'Frank Sinatra' or 'Led Zeppelin'.
Working With Dates
A typical entry for a date might look something like this.
mysql> SELECT cds.bought FROM cds;
+------------+
| bought |
+------------+
| 2001-09-01 |
+------------+
1 row in set (0.01 sec)
You could imagine trying to SELECT dates using 'Less Than' or 'More
Than' would be difficult as a date is not a sequential decimal number.
However that is why we specify the 'DATE' datatype when creating the
field
in the table, as this allows comparisons of this type. What actually happens
is that the MySQL DBMS converts any date into the number of days since
year
'0' before doing any comparison.
Try SELECTing cds that you bought prior to the year 2000
mysql> SELECT * FROM cds
-> WHERE (cds.bought < '2001-01-01');
And cds that were bought this century.
mysql> SELECT * FROM cds
-> WHERE (cds.bought >= '2001-01-01');
Other Tricks When Displaying Data
Before leaving the SELECT command alone again for a while, we should touch
upon a few popular ways to control output.
DISTINCT
The DISTINCT qualifier is used to return unique results and is included
as part of the SELECT statement (i.e. before any conditions are applied).
Let us image that our 'cds'
table contained over 2000 rows. If we wanted to look at all the artists
whose
name started with 'E' we might construct a statement like so.
mysql> SELECT artist FROM cds
-> WHERE cds.artist LIKE 'E%';
This would return each row that had an artist whose name started with 'E'.
If that artist has 10 cds in the database his name will be returned 10 times
(once for each cd). We could avoid this by using the DISTINCT qualifier, which
would ensure that each artist was returned only once.
mysql> SELECT DISTINCT cds.artist FROM cds
-> WHERE cds.artist LIKE 'E%';
Hierarchy of Conditions
The conditions that control the filtering of the query exist in
a rough (if not quite exact) hierarchal order:
WHERE
|
GROUP BY
| |
HAVING ORDER BY
| |
LIMIT
If more than one of these conditions are to used in a query then it is recommended
that this order be used, so that GROUP BY cannot go before the WHERE
condition and
LIMIT
cannot go before HAVING etc. Notice that HAVING and ORDER BY are
at the same level - this is because either one can go before the other. Breaking
this hierarchy will generally result in errors.
We have already looked at the WHERE condition extensively, so lets have
a closer look at these conditions.
GROUP BY
When we issue a SELECT command we are shown the results in the order that
the records were entered. We can change this by using the 'GROUP BY' directive,
allowing us to display
the data grouped by field. To return the results ordered by artist:
mysql> SELECT * FROM cds
-> GROUP BY cds.artist;
ORDER BY
Similar to GROUP BY, this condition further allows control over the result
set. ORDER BY controls the sequence of results. For example to display all
the data from the 'cds' table ordered alphabetically by artist
we would issue this command.
mysql> SELECT * FROM cds ORDER BY cds.artist;
You can also choose to sort the results in reverse by appending DESC to the
condition
mysql> SELECT * FROM cds ORDER BY cds.artist DESC;
We can also use two or more ORDER BY conditions, for example if we wanted
to list by artist then the date bought in descending order we could enter.
mysql> SELECT * FROM cds ORDER BY cds.artist, cds.bought DESC;
HAVING
The HAVING condition is really just another WHERE condition that acts as
a 'secondary constraint' on the result set. This works best when you are
trying to apply a restrictive condition after a grouping has taken place.
So for example:
mysql> SELECT * FROM cds
-> GROUP BY cds.artist
-> HAVING cds.title LIKE 'A%';
You should try if at possible to write queries using the WHERE condition
rather than the HAVING condition as HAVING is un-optimised.
LIMIT
There will be times that you create a query that produces a large result
set that you don't want to view or handle all at once. In these situations
it is useful to use the LIMIT condition to restrict the number or records
returned. For example to display the first 5 records that meet a query:
mysql> SELECT * FROM cds LIMIT 5;
To retrieve the rest of the records in batches we can also specify a starting
point before the number or rows to return.
SELECT <fields> FROM <TABLE> LIMIT <starting_point>, <number_of_rows>
So to return rows 6-10 we would specify the start point of 5 and then ask
to return 5 records.
mysql> SELECT * FROM cds LIMIT 5, 5
Or to start at rows 3-7:
mysql> SELECT * FROM cds LIMIT 2, 4
|