160
GAME203 QUERIES & TRANSACTIONS

GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Embed Size (px)

Citation preview

Page 1: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

GAME203QUERIES & TRANSACTIONS

Page 2: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Performing Calculationsin a Query

mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep;+------------+----------+----------------+| first_name | surname | commission + 1 |+------------+----------+----------------+| Sol | Rive | 11 || Charlene | Gordimer | 16 || Mike | Serote | 11 || Mongane | Rive | 11 || Mike | Smith | 13 || Joe | Parisien | 11 || Gord | Mackay | 16 || Ken | Jones | 11 |+------------+----------+----------------+8 rows in set (0.00 sec)

The output shows the result of everyone's commission being increased by 1% without changing the database.

Page 3: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

DATE Functionsmysql> describe sales_rep;

+-----------------+-------------+------+-----+---------+-------+

| Field | Type | Null | Key | Default | Extra |

+-----------------+-------------+------+-----+---------+-------+

| employee_number | int(11) | YES | | NULL | |

| surname | varchar(40) | YES | | NULL | |

| first_name | varchar(30) | YES | | NULL | |

| commission | tinyint(4) | YES | | NULL | |

| date_joined | date | YES | | NULL | |

| birthday | date | YES | | NULL | |

+-----------------+-------------+------+-----+---------+-------+

6 rows in set (0.02 sec)

Page 4: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

DATE Functionsmysql> SELECT date_joined,birthday FROM sales_rep;

+-------------+----------+

| date_joined | birthday |

+-------------+----------+

| NULL | NULL |

| NULL | NULL |

| NULL | NULL |

| NULL | NULL |

| NULL | NULL |

| NULL | NULL |

| NULL | NULL |

+-------------+----------+

7 rows in set (0.00 sec)

Data was never entered into these new fields.

Page 5: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Specifying the Date Format

mysql> select date_format(date_joined, '%m/%d/%Y')

-> from sales_rep where employee_number=1;

+--------------------------------------+

| date_format(date_joined, '%m/%d/%Y') |

+--------------------------------------+

| 02/15/2000 |

+--------------------------------------+

1 row in set (0.00 sec)

Page 6: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Specifying the Date Format

mysql> select date_format(date_joined, '%m/%d/%y')

-> from sales_rep where employee_number=1;

+--------------------------------------+

| date_format(date_joined, '%m/%d/%y') |

+--------------------------------------+

| 02/15/00 |

+--------------------------------------+

1 row in set (0.00 sec)

Page 7: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Specifying the Date Format

mysql> select date_format(date_joined, '%W %M %e %y')

-> from sales_rep where employee_number=1;

+-----------------------------------------+

| date_format(date_joined, '%W %M %e %y') |

+-----------------------------------------+

| Tuesday February 15 00 |

+-----------------------------------------+

1 row in set (0.00 sec)

Page 8: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

mysql> select date_format(date_joined, '%W %M %e, %Y')

-> from sales_rep where employee_number=1;

+------------------------------------------+

| date_format(date_joined, '%W %M %e, %Y') |

+------------------------------------------+

| Tuesday February 15, 2000 |

+------------------------------------------+

1 row in set (0.00 sec)

mysql> select date_format(date_joined, '%a %D %b, %Y')

-> from sales_rep where employee_number=1;

+------------------------------------------+

| date_format(date_joined, '%a %D %b, %Y') |

+------------------------------------------+

| Tue 15th Feb, 2000 |

+------------------------------------------+

1 row in set (0.00 sec)

Page 9: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Returning the Current Date and Time

mysql> SELECT NOW(), CURRENT_DATE();

+---------------------+----------------+

| now() | current_date() |

+---------------------+----------------+

| 2005-01-17 10:15:33 | 2005-01-17 |

+---------------------+----------------+

1 row in set (0.00 sec)

Page 10: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Date and Time Functions

mysql> SELECT YEAR(birthday) FROM sales_rep;+----------------+| year(birthday) |+----------------+| 1976 || 1958 || 1971 || 1982 || 1949 || 1950 || 1965 |+----------------+7 rows in set (0.03 sec)

Here the YEAR function returns the year of each persons birthday from a field that contains data of type DATE.

Page 11: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Year and Date Functionsmysql> SELECT MONTH(birthday), DAYOFMONTH(birthday)

-> FROM sales_rep;+-----------------+----------------------+| month(birthday) | dayofmonth(birthday) |+-----------------+----------------------+| 3 | 18 || 11 | 30 || 6 | 18 || 1 | 4 || 1 | 8 || 3 | 7 || 4 | 7 |+-----------------+----------------------+7 rows in set (0.00 sec)

Here the MONTH and DAYOFMONTH are returned from the birthday field which is of type DATE.

Page 12: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Advanced QueriesGiving Columns a New Heading

mysql> SELECT surname, first_name, month(birthday) -> AS month, dayofmonth(birthday) AS day FROM sales_rep -> ORDER BY month;+----------+------------+-------+------+| surname | first_name | month | day |+----------+------------+-------+------+| Rive | Mongane | 1 | 4 || Smith | Mike | 1 | 8 || Rive | Sol | 3 | 18 || Parisien | Joe | 3 | 7 || Mackay | Gord | 4 | 7 || Serote | Mike | 6 | 18 || Gordimer | Charlene | 11 | 30 |+----------+------------+-------+------+7 rows in set (0.02 sec)

Here we use AS to give columns a new Heading.

Page 13: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Joining Columns with CONCATmysql> SELECT CONCAT(first_name,' ',surname) -> AS name, MONTH(birthday) AS month, DAYOFMONTH(birthday) -> AS day FROM sales_rep ORDER BY month;+-------------------+-------+------+| name | month | day |+-------------------+-------+------+| Mongane Rive | 1 | 4 || Mike Smith | 1 | 8 || Sol Rive | 3 | 18 || Joe Parisien | 3 | 7 || Gord Mackay | 4 | 7 || Mike Serote | 6 | 18 || Charlene Gordimer | 11 | 30 |+-------------------+-------+------+7 rows in set (0.00 sec)

Here we concatenate (join together) two columns into one (first_name and surname).

Page 14: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Finding the Day of the Year

mysql> SELECT DAYOFYEAR(date_joined) FROM sales_rep

-> WHERE employee_number=1;

+------------------------+

| DAYOFYEAR(date_joined) |

+------------------------+

| 46 |

+------------------------+

1 row in set (0.00 sec)

This function will return a value from 1-366.

Page 15: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Date Calculations

mysql> SELECT YEAR(NOW()) – YEAR(birthday) FROM sales_rep;+--------------------------------+

| YEAR(NOW()) – YEAR(birthday) |

+--------------------------------+

| 26 |

| 44 |

| 31 |

| 20 |

+--------------------------------+

4 rows in set (0.00sec)

Returns the difference in years.

Note: CURRENT_DATE() could be used instead of NOW().

Page 16: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Date Calculations● The previous example does not take into account days

and months.● You need to subtract the years as was done previously,

but then subtract a further year if a full year has not passed. Someone born on the 10th of December in 2001 is not one year old in January 2002, but only after the 10th of December 2002.

● Take the MM-DD part components of the two date fields (the current date and the birth date) and compare them. If the current one is larger, a full year has passed. If the current MM-DD part is less than the birth date one, less than a full year has passed, and you must subtract one from the calculation.

Page 17: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Date Calculations

mysql> SELECT YEAR(NOW()) > YEAR(birthday) FROM sales_rep where employee_number=1;

+--------------------------------+| YEAR(NOW()) > YEAR(birthday) |+--------------------------------+| 1 |+--------------------------------+1 rows in set (0.00sec)Mysql evaluatesa true expression to 1 and a false

expression to 0.The current year is greater than the birth date of

employee 1. That is true and evaluates to 1.

Note: CURRENT_DATE() could be used instead of NOW().

Page 18: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Date Calculations

mysql> SELECT YEAR(NOW()) < YEAR(birthday) FROM sales_rep where employee_number=1;

+--------------------------------+| YEAR(NOW()) < YEAR(birthday) |+--------------------------------+| 0 |+--------------------------------+1 rows in set (0.00sec)Mysql evaluatesa true expression to 1 and a false expression

to 0.The current year is not less than the birth date year

employee 1. That is false and evaluates to 0.

Note: CURRENT_DATE() could be used instead of NOW().

Page 19: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Date Calculations● To return just the MM-DD component of the date:

mysql> SELECT RIGHT(CURRENT_DATE,5), RIGHT(birthday,5) FROM sales_rep;

+-----------------------+----------------------+

| RIGHT(CURRENT_DATE,5) | RIGHT(birthday,5) |

+-----------------------+----------------------+

| 04-06 | 03-18 |

| 04-06 | 11-30 |

| 04-06 | 01-04 |

| 04-06 | 06-18 |

+-----------------------+----------------------+

4 rows in set (0.00sec)

The 5 inside the RIGHT( ) function refers to the number of characters from the right side of the string that the function returns. The full string 2004-04-06 returns 04-06.

Page 20: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Date CalculationsMysql> SELECT surname,first_name,(YEAR(CURRENT_DATE)- -> YEAR(birthday)) – (RIGHT(CURRENT_DATE,5) < RIGHT(birthday),5)) -> AS age FROM sales_rep;+----------+------------+-------+| surname | first_name | age |+----------+------------+-------+| Rive | Sol | 26 |+----------+------------+-------+| Gordimer | Charlene | 43 |+----------+------------+-------+| Rive | Mongane | 20 | +----------+------------+-------+| Serote | Mike | 30 |+----------+------------+-------+4 row in set (0.00 sec)

Page 21: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Topics● Logical, arithmetic, comparison, and bit operators● Advanced joins (inner, outer, left, right, and natural joins)● Joining results with UNION● Rewriting sub-selects as joins● Removing records with DELETE and TRUNCATE● User variables● Running MySQL in batch mode● Performing transactions with BEGIN and COMMIT● Consistent reads● Table locks● Read locks for updating and for sharing

Page 22: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Operators

● Logical operators (AND, OR, XOR, NOT)● Arithmetic operators (+, -, * /)● Comparison operators ( >, <, <=, >=, etc)● Bit operators

Page 23: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

True if C1 is false, False if C1 is true

!C1, NOT C1!, NOT

True if either C1 or C2 is true

C1 OR C2,

C1 || C2

OR, ||

Only true if both conditions are true (C1 and C2)

C1 AND C2,

C1 && C2

AND, &&

DescriptionSyntaxOperator

Logical Operators

Page 24: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

mysql> SELECT 1 AND 0;+---------+| 1 AND 0 |+---------+| 0 |+---------+1 row in set (0.00 sec)

mysql> SELECT NOT(1 AND 0);+--------------+| NOT(1 AND 0) |+--------------+| 1 |+--------------+1 row in set (0.00 sec)

mysql> SELECT !((1 OR 0) AND (0 OR 1));+--------------------------+| !((1 OR 0) AND (0 OR 1)) |+--------------------------+| 0 |+--------------------------+1 row in set (0.00 sec)

Page 25: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Arithmetic Operators

a Modulus b

Remainder returned after a/b

a % b%

Division

Quotient returned

a / b/

Multiplicationa * b*

Subtractiona – b-

Additiona + b+

DescriptionSyntaxOperator

Page 26: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

mysql> SELECT 2+1;+-----+| 2+1 |+-----+| 3 |+-----+1 row in set (0.00 sec)

mysql> SELECT 4-2/4;+-------+| 4-2/4 |+-------+| 3.50 |+-------+1 row in set (0.00 sec)

mysql> SELECT 4-(2/4);+---------+| 4-(2/4) |+---------+| 3.50 |+---------+1 row in set (0.00 sec)

mysql> SELECT (4-2)/4;+---------+| (4-2)/4 |+---------+| 0.50 |+---------+1 row in set (0.00 sec)

mysql> SELECT 5 % 3;+-------+| 5 % 3 |+-------+| 2 |+-------+1 row in set (0.00 sec)

Page 27: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Comparison Operators

True if a is not NULLa IS NOT NULLIS NOT NULL

True if a is NULLa is NULLIS NULL

True if a and b are equal including NULL

a<=> b<=>

True if a less or equal to b

a <= b<=

True if a is greater or equal to b

a >= b>=

True if a less than ba < b<

True if a greater than ba > b>

True if Not Equala != b, a <> b !=, <>

True if Equala = b =

DescriptionSyntaxOperator

Page 28: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

a does not matches b with a regular expression

a NOT REGEXP b,a NOT RLIKE b

NOT REGEXP, NOT RLIKE

a matches b with a regular expression

a REGEXP b,a RLIKE b

REGEXP, RLIKE

a does not match any in lista NOT IN (b1,b2,b3..)NOT IN

a equals any in lista IN (b1,b2,b3..)IN

a does not match ba NOT LIKENOT LIKE

a matches ba LIKE bLIKE

a Not Between values b and ca NOT BETWEEN b and c

NOT BETWEEN

a Between values b and ca BETWEEN b and cBETWEEN

Description

True if:

SyntaxOperator

Page 29: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

mysql> SELECT 13=11;+-------+| 13=11 |+-------+| 0 |+-------+1 row in set (0.00 sec)

mysql> SELECT '4200' = 4200.0;+-----------------+| '4200' = 4200.0 |+-----------------+| 1 |+-----------------+1 row in set (0.00 sec)

mysql> SELECT '4200' = '4200.0';+-------------------+| '4200' = '4200.0' |+-------------------+| 0 |+-------------------+1 row in set (0.00 sec)

Page 30: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

mysql> SELECT 'abc' = 'ABC';+---------------+| 'abc' = 'ABC' |+---------------+| 1 |+---------------+1 row in set (0.00 sec)

mysql> SELECT 'abc' = 'ABC ';+----------------+| 'abc' = 'ABC ' |+----------------+| 1 |+----------------+1 row in set (0.02 sec)

mysql> SELECT NULL = 0;+----------+| NULL = 0 |+----------+| NULL |+----------+1 row in set (0.02 sec)

Page 31: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

mysql> SELECT NULL <=> 0;+------------+| NULL <=> 0 |+------------+| 0 |+------------+1 row in set (0.00 sec)

mysql> SELECT 200 = NULL, 200 <> NULL, 200 < NULL, 200 > NULL;+------------+-------------+------------+------------+| 200 = NULL | 200 <> NULL | 200 < NULL | 200 > NULL |+------------+-------------+------------+------------+| NULL | NULL | NULL | NULL |+------------+-------------+------------+------------+1 row in set (0.00 sec)

mysql> SELECT NULL IS NULL;+--------------+| NULL IS NULL |+--------------+| 1 |+--------------+1 row in set (0.00 sec)

Page 32: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

mysql> SELECT 4.5 BETWEEN 4 and 5;+---------------------+| 4.5 BETWEEN 4 and 5 |+---------------------+| 1 |+---------------------+1 row in set (0.00 sec)

mysql> SELECT 5 BETWEEN 6 and 4;+-------------------+| 5 BETWEEN 6 and 4 |+-------------------+| 0 |+-------------------+1 row in set (0.00 sec)

Page 33: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

mysql> SELECT 'abc' < 'b';+-------------+| 'abc' < 'b' |+-------------+| 1 |+-------------+1 row in set (0.00 sec)

mysql> SELECT 'bbc' <= 'b';+--------------+| 'bbc' <= 'b' |+--------------+| 0 |+--------------+1 row in set (0.00 sec)

mysql> SELECT 'a' IN('b','c','a');+---------------------+| 'a' IN('b','c','a') |+---------------------+| 1 |+---------------------+1 row in set (0.02 sec)

Page 34: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

mysql> SELECT 'abcd' LIKE '%b;+--------------------+| 'abcd' LIKE '%b;' |+--------------------+| 0 |+--------------------+1 row in set (0.00 sec)

mysql> SELECT 'abcd' LIKE '%bc%'; % matches zero or more chars.+--------------------+| 'abcd' LIKE '%bc%' |+--------------------+| 1 |+--------------------+1 row in set (0.00 sec)

mysql> SELECT 'abcd' LIKE '%b%';+-------------------+| 'abcd' LIKE '%b%' |+-------------------+| 1 |+-------------------+1 row in set (0.00 sec)

Page 35: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

mysql> SELECT 'abcd' LIKE 'a___';+--------------------+| 'abcd' LIKE 'a___' | _ matches one char+--------------------+| 1 |+--------------------+1 row in set (0.00 sec)

mysql> SELECT 'abcd' LIKE 'a__';+-------------------+| 'abcd' LIKE 'a__' |+-------------------+| 0 |+-------------------+1 row in set (0.00 sec)

Page 36: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Regular Expressions

String must occur at least n times{n,}

Strings must occur exactly n times

{n}

String must occur at least n times, but no more the m

[n, m]

Separates strings|

Anchors match to the end$

Anchors match to beginning^

Matches any digit[0-9]

Match any lower case letter[a-z]

DescriptionCharacter

Page 37: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Matches any character that is (or is not, if ^ is used) either ‘a’, ‘b’, ‘c’, ‘d’ or ‘X’.

‘[a-dX]’, ‘[^a-dX]’

To be more precise, `a{n}' matches exactly `n' instances of `a'.

`a{n,}' matches `n' or more instances of `a'. `a{m,n}' matches

`m' through `n' instances of `a', inclusive.

‘{1}’, ‘{2,3}’

Match zero or more instances of the sequence `abc'.

‘(abc)*’

Matches either of the sequences ‘de’ or ‘abc’. ‘de|abc’

Matches either zero or one `a' character.‘a?’

Matches any sequence of one or more `a' characters.

‘a+’

Matches any sequence of zero or more `a' characters.

‘a*’

Matches any character (including carriage return and newline).

.

DescriptionCharacter

Page 38: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Advanced Joinscreate table customer (id int(11) default NULL,first_name varchar(30) default NULL,surname varchar(40) default NULL) engine=MyISAM;

insert customer values (1,'Yvonne', 'Clegg');insert customer values (2,'Johnny', 'Waston');insert customer values (3,'Winston', 'Powers');insert customer values (4,'Patrica', 'Manning');

Page 39: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Advanced Joinscreate table sales (code int(11) default NULL,sales_rep int(11) default NULL,customer int(11) default NULL,value int(11) default NULL) ENGINE=MySQL;

insert into sales_rep values (1,1,1,2000);insert into sales_rep values (2,4,3,250);insert into sales_rep values (3,2,3,500;insert into sales_rep values (4,1,4,450);insert into sales_rep values (5,3,1,3800);insert into sales_rep values (6,1,2,500);

Page 40: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Advanced Joins

create table sales_rep (employee_number int(11) default NULL,surname varchar(40) default NULL,first_name varchar(30) default NULL,commission tinyint(4) default NULL,date_joined date default NULL,birthday date default NULL) ENGINE=MyISAM;

insert into sales_rep values (1,'Rive','Sol',10,'2000-02-15','1976-03-18');insert into sales_rep values (2,'Gordimer','Clarlene',15,'1998-07-09','1958-11-30');insert into sales_rep values (3,'Serote','Mike',10,'2001-05-14','1971-16-18');insert into sales_rep values (4,'Rive','Mongane','10,'2002-11-23'.'1982-01-04');

Page 41: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Basic Joins

mysql> mysql> SELECT sales_rep, customer, value, first_name, surname -> FROM sales, sales_rep -> WHERE code=1 AND -> sales_rep.employee_number=sales.sales_rep;+-----------+----------+-------+------------+---------+| sales_rep | customer | value | first_name | surname |+-----------+----------+-------+------------+---------+| 1 | 1 | 2000 | Sol | Rive |+-----------+----------+-------+------------+---------+1 row in set (0.00 sec)

Note: The sales_rep.employee_number and sales.sales_rep form the join condition in the WHERE clause.

Page 42: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

More Complex Joinmysql> SELECT sales_rep, customer.first_name, sales_rep.surname, -> value, customer.first_name, customer.surname -> FROM sales, sales_rep, customer -> WHERE sales_rep.employee_number = sales.sales_rep AND -> customer.id = sales.customer;+-----------+------------+----------+-------+------------+---------+| sales_rep | first_name | surname | value | first_name | surname |+-----------+------------+----------+-------+------------+---------+| 1 | Yvonne | Rive | 2000 | Yvonne | Clegg || 3 | Yvonne | Serote | 3800 | Yvonne | Clegg || 1 | Johnny | Rive | 500 | Johnny | Jones || 2 | Winston | Gordimer | 500 | Winston | Powers || 4 | Winston | Rive | 250 | Winston | Powers || 1 | Patricia | Rive | 450 | Patricia | Clark |+-----------+------------+----------+-------+------------+---------+6 rows in set (0.00 sec)Note: Here we have two join conditions:

sales_rep.employee_number = sales.sales_rep ANDcustomer.id = sales.customer

Result: Lists all the sales for which there are corresponding rows in both the sales_rep and customer tables

Page 43: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

sales;+------+-----------+----------+-------+| code | sales_rep | customer | value |+------+-----------+----------+-------+| 1 | 1 | 1 | 2000 || 2 | 4 | 3 | 250 || 3 | 2 | 3 | 500 || 4 | 1 | 4 | 450 || 5 | 3 | 1 | 3800 || 6 | 1 | 2 | 500 |+------+-----------+----------+-------+

sales_rep;+-----------------+----------+------------+------------+-------------+------------+| employee_number | surname | first_name | commission | date_joined | birthday |+-----------------+----------+------------+------------+-------------+------------+| 1 | Rive | Sol | 10 | 2000-02-15 | 1976-03-18 || 2 | Gordimer | Charlene | 15 | 1998-07-09 | 1958-11-30 || 3 | Serote | Mike | 10 | 2001-05-04 | 1971-06-18 || 4 | Rive | Mongane | 10 | 2002-11-23 | 1982-01-04 |+-----------------+----------+------------+------------+-------------+------------+

customer;+------+------------+---------+| id | first_name | surname |+------+------------+---------+| 1 | Yvonne | Clegg || 2 | Johnny | Jones || 3 | Winston | Powers || 4 | Patricia | Clark |+------+------------+---------+

Page 44: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Inner Joins – (Same as Basic Join)mysql> SELECT first_name, surname, value -> FROM customer, sales -> WHERE id=customer;+------------+---------+-------+| first_name | surname | value |+------------+---------+-------+| Yvonne | Clegg | 2000 || Winston | Powers | 250 || Winston | Powers | 500 || Patricia | Clark | 450 || Yvonne | Clegg | 3800 || Johnny | Jones | 500 |+------------+---------+-------+6 rows in set (0.00 sec)

mysql> SELECT first_name, surname, value -> FROM customer INNER JOIN sales -> ON id=customer;+------------+---------+-------+| first_name | surname | value |+------------+---------+-------+| Yvonne | Clegg | 2000 || Winston | Powers | 250 || Winston | Powers | 500 || Patricia | Clark | 450 || Yvonne | Clegg | 3800 || Johnny | Jones | 500 |+------------+---------+-------+6 rows in set (0.00 sec)

Page 45: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

LEFT Joins (Left Outer Joins)

If a sale was made, where the customer paid cash, and the customer left before you could capture their details, would this cause a problem? No, there’s no problem because you can still add the data to the sales table using a NULL value for customer.

mysql> INSERT INTO sales(code,sales_rep,customer,value) VALUES

-> (7, 2, NULL, 670);

Page 46: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

LEFT Joins

mysql> SELECT sales_rep.first_name, sales_rep.surname, value, -> customer.first_name, customer.surname -> FROM sales, sales_rep, customer -> WHERE sales_rep.employee_number = sales.sales_rep AND -> customer.id = sales.customer;+------------+----------+-------+------------+---------+| first_name | surname | value | first_name | surname |+------------+----------+-------+------------+---------+| Sol | Rive | 2000 | Yvonne | Clegg || Mike | Serote | 3800 | Yvonne | Clegg || Sol | Rive | 500 | Johnny | Jones || Charlene | Gordimer | 500 | Winston | Powers || Mongane | Rive | 250 | Winston | Powers || Sol | Rive | 450 | Patricia | Clark |+------------+----------+-------+------------+---------+6 rows in set (0.02 sec)

Where is the new sale? Because of the customer NULL in the sales table, the join condition is not fulfilled. The = operator excludes NULL values. The solution is to do an OUTER JOIN.

Page 47: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Left (Outer) JoinsA LEFT OUTER JOIN is one which returns all matching rows from the left table, regardless of whether there is a corresponding row in the right table. The syntax for a LEFT JOIN (short for LEFT OUTER JOIN) is a follows: SELECT field1,field2 FROM table1 LEFT JOIN table2 ON field1=field2

mysql> SELECT first_name,surname,value -> FROM sales LEFT JOIN customer -> ON id=customer;+------------+---------+-------+| first_name | surname | value |+------------+---------+-------+| Yvonne | Clegg | 2000 || Winston | Powers | 250 || Winston | Powers | 500 || Patricia | Clark | 450 || Yvonne | Clegg | 3800 || Johnny | Jones | 500 || NULL | NULL | 670 |+------------+---------+-------+7 rows in set (0.01 sec)

Page 48: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Left JoinsTable order in a LEFT JOIN is important. The table from which all matching rows are returned must be the left table (before the LEFT JOIN keyword). Reversing the order will now be shown:

mysql> SELECT first_name,surname,value -> FROM customer LEFT JOIN sales -> ON id=customer;+------------+---------+-------+| first_name | surname | value |+------------+---------+-------+| Yvonne | Clegg | 2000 |Because the left table is| Yvonne | Clegg | 3800 |the customer table, and the| Johnny | Jones | 500 |join matches only those| Winston | Powers | 250 |records that exist in the| Winston | Powers | 500 |left table, the sales record| Patricia | Clark | 450 |with the NULL is not returned.+------------+---------+-------+6 rows in set (0.00 sec)

Page 49: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Extending a LEFT JOIN Across a Third Table

mysql> SELECT sales_rep.first_name, sales_rep.surname, value, -> customer.first_name, customer.surname -> FROM sales LEFT JOIN sales_rep -> ON sales_rep.employee_number = sales.sales_rep -> LEFT JOIN customer -> ON customer.id = sales.customer;+------------+----------+-------+------------+---------+| first_name | surname | value | first_name | surname |+------------+----------+-------+------------+---------+| Sol | Rive | 2000 | Yvonne | Clegg || Mongane | Rive | 250 | Winston | Powers || Charlene | Gordimer | 500 | Winston | Powers || Sol | Rive | 450 | Patricia | Clark || Mike | Serote | 3800 | Yvonne | Clegg || Sol | Rive | 500 | Johnny | Jones || Charlene | Gordimer | 670 | NULL | NULL |+------------+----------+-------+------------+---------+7 rows in set (0.00 sec)

Page 50: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

RIGHT Joins (Right Outer Join)Right Joins are exactly the same as left joins, except that the order of the join is reversed.

mysql> SELECT first_name,surname, value -> FROM customer RIGHT JOIN sales ON id=customer;+------------+---------+-------+| first_name | surname | value |+------------+---------+-------+| Yvonne | Clegg | 2000 || Winston | Powers | 250 || Winston | Powers | 500 || Patricia | Clark | 450 || Yvonne | Clegg | 3800 || Johnny | Jones | 500 || NULL | NULL | 670 |+------------+---------+-------+7 rows in set (0.00 sec)

Page 51: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Full Outer Joins● MySQL does not yet support full outer joins.

These are joins where each record from the first table, including those with no match in the second table, is returned along with each record in the second table, including those with no match in the first.

SELECT field1,field2 FROM table1 FULL OUTER JOIN table2

Page 52: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Example Showing How To Do A Full Outer JoinIn this example we have two tables, A and B:

A:+----+| id | Note: Table A does not contain D +----+| A || B || C |+----+B:+----+| id | Note: Table B does not contain A+----+| B || C || D |+----+ And we would like to do a query (search) returning ALL rows from both tables. i.e.

ABCD

Page 53: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Code for Full Outer Join

Code:

CREATE temporary TABLE t1unique ASSELECT a.id FROM a LEFT OUTER JOIN b ON a.id = b.idWHERE b.id IS NULL;This will get all rows with ONLY a value in table A. (A)

CREATE temporary TABLE t2unique ASSELECT b.id FROM a RIGHT OUTER JOIN b ON a.id = b.idWHERE a.id IS NULL;This will get all rows with ONLY a value in table B. (D)

CREATE temporary TABLE t3 ASSELECT a.id FROM a, b WHERE a.id = b.id;This will get all rows with matching values in A and B. (B,C)

INSERT INTO t3 SELECT * FROM t1unique;INSERT INTO t3 select * FROM t2unique;This puts the first two queries into the third one... (B,C,A,D)

Page 54: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Code for Full Outer Join

select * from t3 order by id;+----+| id |+----+| A || B || C || D |+----+4 rows in set (0.00 sec)

This might be considered ugly code, I know - but it works.

Cleaning up.

drop table t1unique;drop table t2unique;drop table t3;

Page 55: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Natural Joins

● The id field in the customer table and the customer field in the sales table are related. If you have given them the same name, SQL has a few shortcuts that make the JOIN statements less unwieldy.

mysql> ALTER TABLE sales CHANGE customer id INT;

Page 56: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Natural Joinsmysql> ALTER TABLE sales CHANGE customer id INT;Query OK, 7 rows affected (0.05 sec)Records: 7 Duplicates: 0 Warnings: 0

Now you can perform a natural join.mysql> SELECT first_name, surname, value -> FROM customer NATURAL JOIN sales;+------------+---------+-------+| first_name | surname | value |+------------+---------+-------+| Yvonne | Clegg | 2000 || Winston | Powers | 250 || Winston | Powers | 500 || Patricia | Clark | 450 || Yvonne | Clegg | 3800 || Johnny | Jones | 500 |+------------+---------+-------+6 rows in set (0.00 sec)

Page 57: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Natural JoinsThe previous SELECT is identical to the following:

mysql> SELECT first_name, surname, value -> FROM customer INNER JOIN sales -> ON customer.id = sales.id;+------------+---------+-------+| first_name | surname | value |+------------+---------+-------+| Yvonne | Clegg | 2000 || Winston | Powers | 250 || Winston | Powers | 500 || Patricia | Clark | 450 || Yvonne | Clegg | 3800 || Johnny | Jones | 500 |+------------+---------+-------+6 rows in set (0.00 sec)

Page 58: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Natural Left or Right JoinsA NATURAL JOIN can also be a LEFT OR RIGHT JOIN:

mysql> SELECT first_name, surname, value -> FROM customer LEFT JOIN sales -> ON customer.id = sales.id;+------------+---------+-------+| first_name | surname | value |+------------+---------+-------+| Yvonne | Clegg | 2000 || Yvonne | Clegg | 3800 || Johnny | Jones | 500 || Winston | Powers | 250 || Winston | Powers | 500 || Patricia | Clark | 450 |+------------+---------+-------+6 rows in set (0.00 sec)

See the next slide for the equivalent natural join.

Page 59: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Natural LEFT JOIN

mysql> SELECT first_name, surname, value -> FROM customer NATURAL LEFT JOIN sales;+------------+---------+-------+| first_name | surname | value |+------------+---------+-------+| Yvonne | Clegg | 2000 || Yvonne | Clegg | 3800 || Johnny | Jones | 500 || Winston | Powers | 250 || Winston | Powers | 500 || Patricia | Clark | 450 |+------------+---------+-------+6 rows in set (0.00 sec)

Page 60: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

The USING CLAUSE● The USING keyword allows a bit more control than a

NATURAL JOIN. If there is more than one identical field in the two tables, this keyword allows you to specify which of these fields are used as join conditions. The following two tables A and B have identical fields a,b,c,d. The following are equivalent:

SELECT * FROM A LEFT JOIN B USING (a,b,c,d)SELECT * FROM A NATURAL LEFT JOIN B

The USING keyword allows you to specify only some of the four identical fields:

SELECT * FROM A LEFT JOIN B USING (a,d)Note: For purposes of the NATURAL JOIN, identical means

identical in name, not in type. The two id fields could be INT and DECIMAL, or even INT and VARCHAR, as long as they have the same name.

Page 61: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Returning Results Found in One Table, but Not the Other

mysql> INSERT INTO sales_rep VALUES -> (5, 'Jomo', 'Ignesund', 10, '2002-11-29', '1968-12-01');Query OK, 1 row affected (0.05 sec)

mysql> SELECT DISTINCT first_name, surname -> FROM sales_rep INNER JOIN sales ON sales_rep=employee_number;+------------+----------+| first_name | surname |+------------+----------+ All the sale_reps that have| Sol | Rive | made a sale are listed.| Mongane | Rive || Charlene | Gordimer || Mike | Serote |+------------+----------+4 rows in set (0.07 sec)

Page 62: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

The reverse is also useful. To find out which sales rep appears in the sales_rep table but has no corresponding entry in the sales table.

mysql> SELECT first_name, surname -> FROM sales_rep LEFT JOIN sales -> ON sales_rep=employee_number -> WHERE sales_rep IS NULL;+------------+---------+| first_name | surname |+------------+---------+| Ignesund | Jomo |+------------+---------+1 row in set (0.00 sec)

Page 63: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Joining Results with UNION

● UNION is used to combine the result from many SELECT statements into one result set. UNION is available from MySQL 4.0.0 on.

SELECT …..

UNION [ALL | DISTINCT]

SELECT …..

[UNION [ALL | DISTINCT]

SELECT ….];

Page 64: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

● Selected columns listed in corresponding positions of each SELECT statement should have the same type.

● The column names used in the first SELECT statement are used as the column names for the results returned.

● If you don’t use the keyword ALL for the UNION, all returned rows will by unique, as if you had done a DISTINCT for the total result set. If you specify ALL, you will get all matching rows from all the used SELECT statements.

● The DISTINCT keyword is an optional word as this is the default.

● You cannot mix UNION ALL and UNION DISTINCT in the same query. If you use ALL for one UNION then it is used for all of them.

Page 65: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Joining Results with UNION

mysql> CREATE TABLE old_customer (id INT, first_name VARCHAR(30), -> surname VARCHAR(40));Query OK, 0 rows affected (0.14 sec)

mysql> INSERT INTO old_customer VALUES (5432, 'Thulani', 'Salie'), -> (2342, 'Shahiem', 'Papo');Query OK, 2 rows affected (0.04 sec)Records: 2 Duplicates: 0 Warnings: 0mysql> SELECT id, first_name, surname FROM old_customer -> UNION SELECT id, first_name, surname -> FROM customer;+------+------------+---------+| id | first_name | surname |+------+------------+---------+| 5432 | Thulani | Salie || 2342 | Shahiem | Papo || 1 | Yvonne | Clegg || 2 | Johnny | Jones || 3 | Winston | Powers || 4 | Patricia | Clark |+------+------------+---------+6 rows in set (0.02 sec)

Page 66: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

UNION with ORDER BYmysql> SELECT id, first_name, surname FROM old_customer -> UNION -> SELECT id, first_name, surname FROM customer -> ORDER BY surname, first_name;+------+------------+---------+| id | first_name | surname |+------+------------+---------+| 4 | Patricia | Clark || 1 | Yvonne | Clegg |The entire result is sorted| 2 | Johnny | Jones |in ascending order. Use DESC| 2342 | Shahiem | Papo |to sort in descending order.| 3 | Winston | Powers || 5432 | Thulani | Salie |+------+------------+---------+6 rows in set (0.00 sec)

Page 67: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

To Sort Each SELECT Use Parenthesesmysql> (SELECT id, first_name, surname FROM old_customer) -> UNION -> (SELECT id, first_name, surname FROM customer -> ORDER BY surname, first_name);+------+------------+---------+| id | first_name | surname |+------+------------+---------+| 5432 | Thulani | Salie | Sorting the 2nd SELECT.| 2342 | Shahiem | Papo | Did NOT WORK as expected!!| 1 | Yvonne | Clegg | (Customer data should have| 2 | Johnny | Jones | been sorted in ascending| 3 | Winston | Powers | order.)| 4 | Patricia | Clark | No explanation at this time.+------+------------+---------+6 rows in set (0.02 sec)

Although no errors are produced, the ORDER BY clause does not work in MySQL 4.1 when applied to just one of the SELECT clauses. (It has no effect on the output result.) The ORDER BY clause does work when applied to the either output result.

Page 68: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

UNION ALL Returns All Resultsmysql> SELECT id FROM customer UNION ALL SELECT id FROM sales;+------+| id |+------+| 1 || 2 || 3 || 4 || 1 | UNION ALL returns all matching rows from all| 3 | used SELECT statements.| 3 || 4 || 1 || 2 || NULL |+------+11 rows in set (0.00 sec

Page 69: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

UNION requires some thought. You can easily put together unrelated fields as long as the number of fields returned by each select match, and the data types are the same. The results may be meaningless.In this example even the data types are a mismatch.

mysql> (SELECT id, surname FROM customer) UNION ALL (SELECT value, sales_rep FROM sales);+------+---------+| id | surname |+------+---------+| 1 | 0 | - A type mismatch between surname and sales_rep| 2 | 0 | - The surnames are not processed properly.| 3 | 0 | - The results are meaningless.| 4 | 0 | -| 2000 | 1 || 250 | 4 || 500 | 2 || 450 | 1 || 3800 | 3 || 500 | 1 || 670 | 2 |+------+---------+11 rows in set (0.00 sec)

Page 70: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Reversing the SELECTS from the previous example produces different results, but are still meaningless.

mysql> SELECT value, sales_rep FROM sales UNION ALL SELECT id, surname FROM customer;+-------+-----------+| value | sales_rep |+-------+-----------+| 2000 | 1 || 250 | 4 || 500 | 2 || 450 | 1 || 3800 | 3 || 500 | 1 || 670 | 2 || 1 | Clegg | mismatch between sales_rep and surname| 2 | Jones || 3 | Powers || 4 | Clark |+-------+-----------+11 rows in set (0.01 sec)

Page 71: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

UNION and UNION DISTINCT are Equivalent

mysql> SELECT id FROM customer UNION SELECT id FROM sales;+------+| id |+------+| 1 || 2 | UNION Defaults to UNION DISTINCT| 3 || 4 || NULL |+------+5 rows in set (0.03 sec)

mysql> SELECT id FROM customer UNION DISTINCT SELECT id FROM sales;+------+| id |+------+| 1 || 2 | Same RESULT as with UNION| 3 || 4 || NULL |+------+5 rows in set (0.00 sec)

Page 72: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Example DatabaseTables:

client (clientID, name, address, contactPerson, contactNumber)

assignment (clientID, employeeID, workdate, hours)

employee (employeeID, name, job, departmentID)

department (departmentID, name)

employeeSkills (employeeID, skill)

Relationships:

client <-> assignment <-> employee <-> department

^ |

v

employeeSkills

Page 73: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Joining Multiple TablesWe want to know which departments employees have been assigned to work for a client called ‘Telco Inc’. To obtain the wanted data we have to work out a path across four tables starting from the client table where name = ‘Telco Inc’. The ClientID provides a link between the client and assignment tables. The employeeID then links the assignment table to the employee table and finally the departmentID links the employee table to the department table that contains the department name that has been assigned to work for the client. We needed to use three join conditions to join four tables.SELECT department.nameFROM client, assignment, employee, departmentWHERE client.name = ‘Telco Inc’AND client.clientID = assignment.clientIDAND assignment.employeeID = employee.employeeIDAND employee.departmentID = department.departentID;

+--------------------------+| name |+--------------------------+| Research and Development | +--------------------------+1 row in set (0.00 sec)

Page 74: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Joining Multiple TablesThe same result could be obtained using NATURAL JOINS

SELECT department.nameFROM client NATURAL JOIN assignmentNATURAL JOIN employee NATURAL JOIN department;+--------------------------+| name |+--------------------------+| Research and Development | +--------------------------+1 row in set (0.00 sec)

Page 75: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Sub-Selects

● Many queries make use of a SELECT within a SELECT.

● Sub-selects were introduced with MySQL 4.1.

● In many cases, you can rewrite a subselect as a join

Page 76: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Sub-queries (Sub-selects)

• Sub-queries do not add new functionality , but queries are often more readable using sub-queries, rather than a complex set of joins. Two basic kinds of sub-queries have been added to MySQL:

– Derived table sub-queries– Expression sub-queries

• Sub-queries that return a single value or row• Sub-queries that are used to test a Boolean expression

Page 77: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Example DatabaseTables:

client (clientID, name, address, contactPerson, contactNumber)

assignment (clientID, employeeID, workdate, hours)

employee (employeeID, name, job, departmentID)

department (departmentID, name)

employeeSkills (employeeID, skill)

Relationships:

client <-> assignment <-> employee <-> department

^ |

v

employeeSkills

Page 78: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Using Derived Table Sub-queries Derived table sub-queries allow us to list a query in the FROM clause of another

query. This effectively allows us to create a temporary table and add it to the query. Consider the following simple query:

SELECT employeeID, name FROM employee WHERE job=’programmer’;

This will retrieve the employeeID and name of the individual that matches and is identified by job ‘programmer’. We can use this query within another query:

Page 79: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Using Derived Table Sub-queries

The sub-query is found in the FROM portion of a SELECT statement when using derived table sub-queries.

SELECT programmer.name FROM(SELECT employeeID, name FROM employee WHERE job=’programmer’;)

AS programmer, assignmentWHERE programmer.employeeID = assignment.employeeID;

The sub-query makes a derived table that contains only the rows employeeID and name, and in this example, we have aliased this table to call it ‘programmer’. The outer FROM clause contains two tables, the derived table called programmer and the assignment table.+--------------+| name |+--------------+| Nora Edwards |+--------------+1 row in set(0.01 sec)

Page 80: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Using Single-Value Sub-queriesWe start with a simple query

SELECT MAX(hours) FROM assignment;

Single-value sub-queries return a single column value and are then typically used for comparison.

SELECT e.employee, e.nameFROM employee AS e, assignment AS aWHERE e.employeeID = a.employeeIDAND a.hours = (SELECT MAX(hours) FROM assignment);

Here, we are looking for what might be termed the company’s hardest working employee: Who is the employee who has put in the greatest number of hours on a particular day on an assignment?

Page 81: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Using Boolean Expression Sub-queries

Boolean expression sub-queries are used to check our query against some special functions that return a Boolean expression. These special functions are IN, EXISTS, and (grouped together) ALL, ANY and SOME.

We can use the keyword IN to check against a set of values. Consider the following query:

SELECT name FROM employeeWHERE employeeID NOT IN (SELECT employeeID FROM assignment);

This query allows us to look for employees who are not in a set of employees who have worked on an outside assignment. The keyword IN lets us look for values in a set of values. The same result could be provided by a NATURAL LEFT JOIN between tables employee and assignment.

SELECT name FROM employeeWHERE employee NATURAL LEFT JOIN assignment;

Page 82: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Using Boolean Expression Sub-queries

Another use of NOT IN is to just test against a listed set of values, as shown here:

SELECT nameFROM employeeWHERE employeeID NOT IN (6651, 1234);

Page 83: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Using Boolean Expression Sub-queriesThe EXIST keyword works in a slightly different fashion than the IN keyword. With EXIST, we use data from the outer query in the sub-query. Consider the following query:

SELECT e.name, e.employeeIDFROM employee AS eWHERE NOT EXISTS

(SELECT * FROM assignment WHERE employeeID = e.employeeID)

Here, we are looking for employees who have never worked on an outside assignment. For each row in the employee table, we check the result of the sub-query, and if there is no matching row (WHERE NOT EXISTS), we add the employee’s details to the result set. Note, that the same result can be obtained using a LEFT JOIN, which is also more efficient.

Page 84: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Using Boolean Expression Sub-queriesThe ALL, ANY, and SOME keywords are used to compare against a set of values returned from a sub-query.

Consider the following query:

SELECT e.nameFROM employee AS e, assignment AS aWHERE e.employeeID = a.employeeIDAND a.hours > ALL

(SELECT a.hoursFROM assignment AS a, employee AS eWHERE e.employeeID = a.employeeIDAND e.job = ‘Programmer’);

The sub-query finds a list of hours worked on assignments by programmers in the company. It then looks for any other employees who have worked on an assignment for longer than these programmers, using the check a.hours > ALL (the programmers hours). If this query returns no rows, then nobody in this company works longer hours than the programmers.

Page 85: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

mysql> select * from sales;+------+-----------+------+-------+| code | sales_rep | id | value |+------+-----------+------+-------+| 1 | 1 | 1 | 2000 || 2 | 4 | 3 | 250 || 3 | 2 | 3 | 500 || 4 | 1 | 4 | 450 || 5 | 3 | 1 | 3800 || 6 | 1 | 2 | 500 || 7 | 2 | NULL | 670 |+------+-----------+------+-------+7 rows in set (0.00 sec)

mysql> select * from sales_rep;+-----------------+----------+------------+------------+-------------+------------+| employee_number | surname | first_name | commission | date_joined | birthday |+-----------------+----------+------------+------------+-------------+------------+| 1 | Rive | Sol | 10 | 2000-02-15 | 1976-03-18 || 2 | Gordimer | Charlene | 15 | 1998-07-09 | 1958-11-30 || 3 | Serote | Mike | 10 | 2001-05-04 | 1971-06-18 || 4 | Rive | Mongane | 10 | 2002-11-23 | 1982-01-04 || 5 | Jomo | Ignesund | 10 | 2002-11-29 | 1968-12-01 |+-----------------+----------+------------+------------+-------------+------------+5 rows in set (0.00 sec)

mysql> select * from customer;+------+------------+---------+| id | first_name | surname |+------+------------+---------+| 1 | Yvonne | Clegg || 2 | Johnny | Jones || 3 | Winston | Powers || 4 | Patricia | Clark |+------+------------+---------+4 rows in set (0.00 sec)

Page 86: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Sub-selectsWe want to return the names of all sales reps who made a sale with a value greater than 1000.

mysql> SELECT first_name, surname FROM sales_rep -> WHERE sales_rep.employee_number IN -> (SELECT sales_rep FROM sales -> WHERE value > 1000);+------------+---------+| first_name | surname |+------------+---------+| Sol | Rive || Mike | Serote |+------------+---------+2 rows in set (0.00 sec)

The following two slides show how this statement works. The inner select is executed first followed by the outer select.

Page 87: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

The inner selectmysql> SELECT sales_rep FROM sales WHERE value > 1000;+-----------+| sales_rep |+-----------+| 1 | | 3 |+-----------+2 rows in set (0.00 sec)

Page 88: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

The outer selectThe values 1 and 3 that were returned from the inner select are now used with the outer select to get the sales reps.mysql> SELECT first_name, surname FROM sales_rep -> WHERE sales_rep.employee_number IN (1);+------------+---------+| first_name | surname |+------------+---------+| Sol | Rive |+------------+---------+1 row in set (0.00 sec)

mysql> SELECT first_name, surname FROM sales_rep -> WHERE sales_rep.employee_number IN (3);+------------+---------+| first_name | surname |+------------+---------+| Mike | Serote |+------------+---------+1 row in set (0.00 sec)

Page 89: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Same Result Using an INNER JOIN

The previous example can be rewritten as an INNER JOIN.mysql> SELECT DISTINCT first_name, surname -> FROM sales_rep INNER JOIN sales -> ON employee_number = sales_rep -> WHERE value > 1000;+------------+---------+| first_name | surname |+------------+---------+| Sol | Rive || Mike | Serote |+------------+---------+2 rows in set (0.02 sec)

Page 90: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Same result using acompound-where clause

mysql> SELECT DISTINCT first_name, surname -> FROM sales_rep, sales -> WHERE sales.sales_rep = sales_rep.employee_number -> AND value > 1000;+------------+---------+| first_name | surname |+------------+---------+| Sol | Rive || Mike | Serote |+------------+---------+2 rows in set (0.00 sec)

Page 91: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Sales Reps that have not made a salemysql> SELECT first_name, surname FROM sales_rep

-> WHERE employee_number -> NOT IN (SELECT DISTINCT sales_rep FROM sales);+------------+---------+| first_name | surname |+------------+---------+| Ignesund | Jomo | single-value sub-query is used+------------+---------+1 row in set (0.02 sec)

A alternate (better) way uses a LEFT JOIN as follows:mysql> SELECT DISTINCT first_name, surname -> FROM sales_rep LEFT JOIN sales -> ON sales_rep=employee_number -> WHERE sales_rep IS NULL;+------------+---------+| first_name | surname |+------------+---------+| Ignesund | Jomo |+------------+---------+1 row in set (0.00 sec)

Page 92: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Adding Records to a Table from Other Tables using INSERT SELECT

The INSERT statement can be used to add records, or parts of records, that exist in other tables. We will create a new table containing the customer names and the value of all purchases they have made. The following query would return the needed results:

mysql> SELECT first_name, surname, SUM(value) -> FROM sales NATURAL JOIN customer -> GROUP BY first_name, surname;+------------+---------+------------+| first_name | surname | SUM(value) |+------------+---------+------------+| Johnny | Jones | 500 || Patricia | Clark | 450 || Winston | Powers | 750 || Yvonne | Clegg | 5800 |+------------+---------+------------+4 rows in set (0.00 sec)

Page 93: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Create the table that will receive the results:mysql> CREATE TABLE customer_sales_values -> (first_name VARCHAR(30), -> surname VARCHAR(40), -> value INT);Query OK, 0 rows affected (0.09 sec)Insert the results into the table using a INSERT SELECT statement:mysql> INSERT INTO customer_sales_values -> (first_name, surname, value) -> SELECT first_name, surname, SUM(value) -> FROM sales NATURAL JOIN customer -> GROUP BY first_name, surname;Query OK, 4 rows affected (0.02 sec)Records: 4 Duplicates: 0 Warnings: 0

mysql> SELECT * FROM customer_sales_values;+------------+---------+-------+| first_name | surname | value |+------------+---------+-------+| Johnny | Jones | 500 || Patricia | Clark | 450 || Winston | Powers | 750 || Yvonne | Clegg | 5800 |+------------+---------+-------+4 rows in set (0.00 sec)

Page 94: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

More about Adding Records

Instead of using the following to insert records:

mysql> INSERT INTO customer_sales_values -> (first_name, surname, value) -> VALUES ('Charles', 'Dube',0);Query OK, 1 row affected (0.00 sec)

You could use this:

mysql> INSERT INTO customer_sales_values SET -> first_name='Charles', surname='Dube', value=0;Query OK, 1 row affected (0.00 sec)

Page 95: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

You can also do a limited form of calculation when you add records. To demonstrate this, we will add another field to the customer_sales_value table:

mysql> ALTER TABLE customer_sales_values ADD value2 INT;Query OK, 5 rows affected (0.13 sec)Records: 5 Duplicates: 0 Warnings: 0

We will now do an INSERT into this table, and populate value2 with a value that is twice the size of value.

mysql> INSERT INTO customer_sales_values -> (first_name, surname, value, value2) -> VALUES ('Gladys', 'Malherbe', 5, value*2);Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM customer_sales_values -> WHERE first_name='Gladys';+------------+----------+-------+--------+| first_name | surname | value | value2 |+------------+----------+-------+--------+| Gladys | Malherbe | 5 | 10 |+------------+----------+-------+--------+1 row in set (0.00 sec)

Page 96: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

mysql> SELECT * FROM customer_sales_values;+------------+----------+-------+--------+| first_name | surname | value | value2 |+------------+----------+-------+--------+| Johnny | Jones | 500 | NULL || Patricia | Clark | 450 | NULL || Winston | Powers | 750 | NULL || Yvonne | Clegg | 5800 | NULL || Charles | Dube | 0 | NULL || Gladys | Malherbe | 5 | 10 |+------------+----------+-------+--------+6 rows in set (0.00 sec)

Page 97: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Removing Records with DELETE and TRUNCATE

DELETE will remove all records if a WHERE clause is not used to limit the delete. However, DELETE can be very slow in a large table.

mysql> DELETE FROM customer_sales_values;Query OK, 6 rows affected (0.00 sec)

mysql> SELECT * FROM customer_sales_values;Empty set (0.00 sec)

Page 98: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Add records back into customer_sales_values table:

mysql> INSERT INTO customer_sales_values -> (first_name, surname, value, value2) -> VALUES -> ('Johnny','Jones', 500, NULL), -> ('Patricia','Clark',450, NULL), -> ('Winston','Powers', 750, NULL), -> ('Yvonne','Clegg', 5800, NULL), -> ('Charles','Dube', 0, NULL), -> ('Charles','Dube', 0, NULL), -> ('Gladys','Malherbe',5, 10);Query OK, 7 rows affected (0.00 sec)Records: 7 Duplicates: 0 Warnings: 0

Truncate is much faster. It drops and then re-creates the table.mysql> TRUNCATE customer_sales_values;Query OK, 7 rows affected (0.00 sec)

mysql> SELECT * FROM customer_sales_values;Empty set (0.00 sec)

Page 99: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

User VariablesMySQL has a feature that allow the storage of values as temporary variables, which you can use again in a later statement.

The value of a variable is set with the SET statement or in a SELECT statement with :=mysql> SELECT @avg := AVG(commission) FROM sales_rep;+-------------------------+| @avg := AVG(commission) |+-------------------------+| 11.0000 |+-------------------------+1 row in set (0.08 sec)

mysql> SELECT surname,first_name FROM sales_rep WHERE commission > @avg;+----------+------------+| surname | first_name |+----------+------------+| Gordimer | Charlene |+----------+------------+1 row in set (0.02 sec)

Page 100: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

The at(@) sign signifies a MySQL variable.

You can also set a variable specifically: mysql> SET @result = 22/7*33.23;Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @result;+-----------------+| @result |+-----------------+| 104.43714285714 |+-----------------+1 row in set (0.00 sec)

Page 101: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

User variables can be strings, integer or floating-point numbers.

They cannot be used to replace part of a query, such as replacing the name of a table, or used as a literal value in a LIMIT clause.

mysql> SET @t = 'sales';Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM @t;ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@t' at line 1

mysql> mysql> SET @v=2;Query OK, 0 rows affected (0.00 sec)mysql> SELECT * FROM sales LIMIT 0,@v;ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@v' at line 1

Page 102: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

User variables are set in a particular thread or connection to the server, and cannot be accessed by another thread.

mysql> SET @a =1;Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @a;+------+| @a |+------+| 1 |+------+1 row in set (0.00 sec)

You would not be able to access this variable from another thread.mysql> SELECT @a;+------+| @a |+------+| NULL |+------+1 row in set (0.00 sec)

Page 103: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Note that in a SELECT statement, the WHERE clause is calculated first and then the field list. If no records are returned, the user variable will not be set for that statement:

Here, the WHERE clauses does not return a value:

mysql> SELECT @a:=2 FROM sales WHERE value > 10000;Empty set (0.01 sec)

mysql> SELECT @a;+------+| @a |+------+| NULL |+------+1 row in set (0.00 sec)

Page 104: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Here, the WHERE clause does return a value:

mysql> SELECT @a:=2 FROM sales WHERE value > 2000;+-------+| @a:=2 |+-------+| 2 |+-------+1 row in set (0.00 sec)

mysql> SELECT @a;+------+| @a |+------+| 2 |+------+1 row in set (0.01 sec)

Page 105: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

A user variable set in a field list cannot be used as a condition.

mysql> SELECT @d:=2000, value FROM sales WHERE value > @d;Empty set (0.00 sec)

You have to set the variable specifically before the query:

mysql> SET @d=2000;Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @d, value FROM sales WHERE value > @d;+------+-------+| @d | value |+------+-------+| 2000 | 3800 |+------+-------+1 row in set (0.00 sec)

Page 106: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

You can also set a variable in the WHERE clause itself. However, it will not be correctly reflected in the field list unless you reset the variable again.

mysql> SELECT @e, value FROM sales WHERE value > (@e:=2000);+------+-------+| @e | value |+------+-------+| NULL | 3800 |+------+-------+1 row in set (0.01 sec)

mysql> SELECT @f:=2000,value -> FROM sales WHERE value > (@f:=2000);+----------+-------+| @f:=2000 | value |+----------+-------+| 2000 | 3800 |+----------+-------+1 row in set (0.00 sec)

Page 107: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

• Username variables are case sensitive for versions of MySQL prior to version 5.0.

• For SET, either = or := can be used as the assignment operator.

• The general form for issuing a SET statement is:SET @var_name = expr [, @var_name = expr] ….

• The expr assigned to each variable can evaluate to an integer, real, string, or NULL value.

•In non-SET statements the := assignment operator must be used, since the = operators is treated as a comparison operator.

•User variables may be used where expressions are allowed. This does not currently include contexts that explicitly require a number, such as in the LIMIT clause of a SELECT statement, or the IGNORE number LINES clause of a LOAD DATA statement.

• If you refer to a variable that has not been initialized, its value is NULL.

Page 108: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

In a SELECT statement, each expression is evaluated only when sent to the client. This means that in a HAVING, GROUP BY, ORDER BY, or WHERE clause, you cannot refer to an expression that involves variables that are set in the SELECT list. For example, the following statement will not work as expected:

mysql> SELECT (@aa:=id) AS a, (@aa+3) AS b FROM tbl_name HAVING b=5;

The reference to b in the HAVING clause refers to an alias for an expression in the SELECT list that uses @aa. This does not work as expected. @aa will not contain the value of the current row, but the value of id from the previous selected row.

The general rule is to never assign and use the same variable in the same statement.

Page 109: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

• Another issue with setting a variable and using it in the same statement is that the default result type of a variable is based on the type of the variable at the start of the statement. Consider this example:

mysql> SET @a=‘test’;mysql> SELECT @a, (@a:=20) FROM tbl_name;

MySQL will report to the client that column one is a string and convert all accesses of @a to string, even though @a is set to a number for the second column. After the SELECT statement executes, @a will be regarded as a number for the next statement.

To avoid problems with this behaviour, do not set and use variables within a single statement, or else set the variable to 0, 0.0, or ‘’ to define its type before you use it.

An unassigned variable has a value of NULL with a type of string.

Page 110: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Running SQL Statements Stored in FilesCreate a text file, test-1.sql containing the following statements:

INSERT INTO customer(id,first_name,surname) VALUES (5,'Francois','Papo');INSERT INTO customer(id,first_name,surname) VALUES (6,'Neal','Beneke');

You can run these two statements from within your operating system (Linux or Microsoft Windows) command line as follows:

% mysql –u username -p database_name < test-1.sql

mysql> SELECT * FROM customer;+------+------------+---------+| id | first_name | surname |+------+------------+---------+| 1 | Yvonne | Clegg || 6 | Neal | Beneke || 2 | Johnny | Jones || 5 | Francois | Papo || 3 | Winston | Powers || 4 | Patricia | Clark |+------+------------+---------+6 rows in set (0.00 sec)

Page 111: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

If any lines in the file contain errors, MySQL will stop processing the rest of the file. Create a file called test-2.sql to demonstrate this:

DELETE FROM customer WHERE id >= 6;INSERT INTO customer(id,first_name,surname) VALUES (6,'Neal','Beneke');INSERT INTO customer(id,first_name,surname) VALUES (,'Sandile','Cohen');INSERT INTO customer(id,first_name,surname) VALUES (7,'Winnie','Dlamini');

C:\slc>mysql -u parisien -p mod3 < test-2.sqlEnter password: *******ERROR 1064 (42000) at line 3: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''Sandile','Cohen')' at line 1

mysql> SELECT * FROM customer;+------+------------+---------+| id | first_name | surname |+------+------------+---------+| 1 | Yvonne | Clegg || 6 | Neal | Beneke | Only the first record| 2 | Johnny | Jones | has been inserted. The| 5 | Francois | Papo | error on line 3 stopped| 3 | Winston | Powers | further processing of| 4 | Patricia | Clark | the file.+------+------------+---------+6 rows in set (0.00 sec)

Page 112: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

You can force MySQL to continue processing even if there are errors with the force option (-f).

C:\slc>mysql -f -u parisien -p mod3 < test-2.sqlEnter password: *******ERROR 1064 (42000) at line 3: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''Sandile','Cohen')' at line 1

mysql> SELECT * FROM customer;+------+------------+---------+| id | first_name | surname |+------+------------+---------+| 1 | Yvonne | Clegg || 6 | Neal | Beneke | The error is still| 2 | Johnny | Jones | reported, but all valid| 5 | Francois | Papo | records have been| 3 | Winston | Powers | inserted.| 4 | Patricia | Clark || 7 | Winnie | Dlamini | << added +------+------------+---------+7 rows in set (0.00 sec)

Page 113: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Redirecting Output to a FileYou can also capture the output to another file. Consider the following example. Instead of running your SELECT statement from the MySQL command line, you can add it to the script file test-3.sql.

DELETE FROM customer WHERE id >= 6;INSERT INTO customer(id,first_name,surname) VALUES (6,'Neal','Beneke');INSERT INTO customer(id,first_name,surname) VALUES (7,'Winnie','Dlamini');SELECT * FROM customer;

C:\slc>mysql -u parisien -p mod3 < test-3.sql > test_output.txtEnter password: *******

id first_name surname1 Yvonne Clegg7 Winnie Dlamini2 Johnny Jones5 Francois Papo3 Winston Powers4 Patricia Clark6 Neal Beneke

The data is tab delimited, and there is no formatting lines in the test_output.txt file.

Page 114: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Using Files from Within the MySQL Command Line

You can also run SQL statements stored in a file from the command line in MySQL with the SOURCE command:

mysql> SOURCE test-3.sqlQuery OK, 2 rows affected (0.00 sec)

Query OK, 1 row affected (0.00 sec)

Query OK, 1 row affected (0.00 sec)

+------+------------+---------+| id | first_name | surname |+------+------------+---------+| 1 | Yvonne | Clegg || 7 | Winnie | Dlamini || 2 | Johnny | Jones || 5 | Francois | Papo || 3 | Winston | Powers || 4 | Patricia | Clark || 6 | Neal | Beneke |+------+------------+---------+7 rows in set (0.00 sec)

Page 115: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

I will now delete the records that were added to demonstrate the INSERTING of records using script files.

mysql> DELETE FROM customer WHERE id > 4;Query OK, 3 rows affected (0.00 sec)

mysql> SELECT * FROM customer;+------+------------+---------+| id | first_name | surname |+------+------------+---------+| 1 | Yvonne | Clegg || 2 | Johnny | Jones || 3 | Winston | Powers || 4 | Patricia | Clark |+------+------------+---------+4 rows in set (0.00 sec)

Page 116: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Transactions and Locking• Database queries run one after another.

• Some kinds of queries need to be performed in a specific order, such as those that are dependent on the results of a previous query or group of updates that need to be done as a whole.

•All table types can make use of some form of locking, but only InnoDB and BDB tables have transactional capabilities built in.

Page 117: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

What are Transactions• With respect to database management systems, a transaction is a sequence of related instructions that must be treated as one indivisible unit.

• All of the work in the transaction must be done, or all of it must be left undone. This concept is known as atomicity. A transaction is atomic because it cannot be broken down into parts – it all gets processed or it all gets ignored.

• Atomicity is particularly important when considering concurrent access by multiple users, processes, or threads and also for recovery. Each user, program, process, or thread may need access to the database server, and must not interfere with each other when running concurrently.

• If an error occurs, the database must honour transactions when recovering. This means returning the database to the state it was in before the error occurred or finishing the whole transaction. It is better to lose an entire transaction of related changes than to recover to a state partway through a sequence of updates that might result in the database being in an inconsistent state.

Page 118: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Example Database: accountThe following database contains back account details:

mysql> CREATE TABLE account ( -> number INT NOT NULL AUTO_INCREMENT PRIMARY KEY, -> balance FLOAT) TYPE=InnoDB;Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> INSERT INTO account (balance) VALUES (0.0);Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO account (balance) VALUES (1000.0);Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO account (balance) VALUES (2000.0);Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM account;+--------+---------+| number | balance | Three bank accounts contained in one table!!+--------+---------+ | 1 | 0 || 2 | 1000 | It does not matter in what order the above INSERTs| 3 | 2000 | are run, since each modifies a different record.+--------+---------+3 rows in set (0.00 sec)

Page 119: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

For more complex queries or sets of queries, the order of execution can be very important. Consider the following statements that are intended to deposit $500 into account 2:

mysql> # first check balance from account where number = 2mysql> SELECT balance FROM account WHERE number = 2;+---------+| balance |+---------+| 1000 |+---------+1 row in set (0.00 sec)

mysql> # Now store updated balancemysql> UPDATE account SET balance = 1500 WHERE number = 2;Query OK, 1 row affected (0.01 sec)Rows matched: 1 Changed: 1 Warnings: 0

If other clients can update the balance of this account between our balance check and our balance update, we may not get the result we expected. These queries are related, and need to be run together.

Page 120: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

If two clients were running pairs of queries like this at the same time, our final result would depend on timing. If one client was attempting to deposit $500 with these queries and the second client was attempting to deposit $100 with the following pair, the end result could be a balance of $1100, $1500 or $1600 – only the last result is correct.mysql> # first check balance from account where number = 2mysql> SELECT balance FROM account WHERE number = 2;+---------+| balance |+---------+| 1000 |+---------+1 row in set (0.00 sec)mysql> UPDATE account SET balance = 1100 WHERE number = 2;Query OK, 1 row affected (0.00 sec)Rows matched: 1 Changed: 1 Warnings: 0mysql> SELECT * FROM account;+--------+---------+| number | balance |+--------+---------+| 1 | 0 || 2 | 1100 | result could be 1100, 1500 or 1600.| 3 | 2000 |+--------+---------+3 rows in set (0.00 sec)

Page 121: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Relative UpdatesMaking our updates relative rather than absolute will make them into a single, indivisible unit and will solve this problem. The following query will run correctly, regardless of what other queries are running at the same time.mysql> UPDATE account SET balance = balance + 500 WHERE number = 2;Query OK, 1 row affected (0.00 sec)Rows matched: 1 Changed: 1 Warnings: 0

A single update statement in MySQL is always atomic. It cannot be interrupted by another query or half succeed. It will complete or will completely fail on an error.

Page 122: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

More Complex ScenariosConsider the following pair of queries intended to transfer $1000 from account 2 to account 1:

mysql> UPDATE account SET balance = balance - 1000 WHERE number = 2;Query OK, 1 row affected (0.00 sec)Rows matched: 1 Changed: 1 Warnings: 0

mysql> UPDATE account SET balance = balance + 1000 WHERE number = 1;Query OK, 1 row affected (0.00 sec)Rows matched: 1 Changed: 1 Warnings: 0

mysql> SELECT * FROM account;+--------+---------+| number | balance | It is important that both queries run together for+--------+---------+ sensible results. The total amount of money in the| 1 | 1000 | system should be the same after the queries as| 2 | 600 | before. | 3 | 2000 | If a power failure occurred between UPDATES, our+--------+---------+ data would no longer be consistent.3 rows in set (0.00 sec)

Page 123: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

A simple workaround is to collapse the queries into one SQL statement.mysql> UPDATE account AS source, account AS dest -> SET source.balance = source.balance - 1000, -> dest.balance = dest.balance + 1000 -> WHERE source.number = 2 AND dest.number = 1;Query OK, 2 rows affected (0.00 sec)Rows matched: 2 Changed: 2 Warnings: 0

mysql> SELECT * FROM account;+--------+---------+| number | balance | We have produced one atomic update.+--------+---------+| 1 | 1000 | The combined query is harder to read| 2 | 600 | and debug than our first attempt.| 3 | 2000 |+--------+---------+3 rows in set (0.00 sec)

In many cases, it is not possible to collapse all the related queries into one statement. Transactions can be used to mark a set of statements so they are treated as one.

Page 124: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

mysql> START TRANSACTION;Query OK, 0 rows affected (0.00 sec)

mysql> UPDATE account SET balance = balance - 1000 WHERE number = 2;Query OK, 1 row affected (0.00 sec)Rows matched: 1 Changed: 1 Warnings: 0

mysql> UPDATE account SET balance = balance + 1000 WHERE number = 1;Query OK, 1 row affected (0.00 sec)Rows matched: 1 Changed: 1 Warnings: 0

mysql> COMMIT;Query OK, 0 rows affected (0.19 sec)

mysql> SELECT * FROM account;+--------+---------+| number | balance |+--------+---------+| 1 | 1000 || 2 | 600 || 3 | 2000 |+--------+---------+3 rows in set (0.00 sec)

Page 125: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

TRANSACTION FEATURE SUMMARY

• An important property of transactions is that they are not visible to other sessions until they are complete and committed.

• No other thread can read inconsistent data from the table(s) while you are in the process of updating them.

• Another benefit of transactions is that partially performed transactions can be undone. As long as we attempt to roll back the transaction before we have committed it, then any changes made by queries that are part of the transaction will be undone.

(In the example on the next slide, we use a SELECT to check that we are not removing more money from the source account than it contains. We use the rollback command to cancel the whole transaction. Using a roll back leaves no trace in the data. Because partial results were never visible to other sessions, it is exactly as though it never happened.)

Page 126: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

mysql> START TRANSACTION;Query OK, 0 rows affected (0.00 sec)

mysql> UPDATE account SET balance = balance - 1000 WHERE number = 2;Query OK, 1 row affected (0.00 sec)Rows matched: 1 Changed: 1 Warnings: 0

mysql> UPDATE account SET balance = balance + 1000 WHERE number = 1;Query OK, 1 row affected (0.00 sec)Rows matched: 1 Changed: 1 Warnings: 0

mysql> SELECT balance FROM account WHERE number = 2;+---------+| balance |+---------+| -400 | Account is in the RED!!+---------+1 row in set (0.00 sec)

mysql> ROLLBACK; Roll Back changes.Query OK, 0 rows affected (0.00 sec)

mysql> SELECT balance FROM account WHERE number = 2;+---------+| balance |+---------+| 600 | Account has been restored.+---------+1 row in set (0.00 sec)

Page 127: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

MyISAM Tables• MyISAM is a non-transaction-safe table type.

• All your changes are committed immediately.

• Grouping your statements with START TRANSACTION and COMMIT will have no effect on non-transactional-safe tables.

• You can even call ROLLBACK. It will not give an error – it will just have no effect on anything you have altered in a non-transaction-safe table.

Page 128: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Using LOCKS• An alternative way of obtaining some of the benefits of a transaction is to manually lock and unlock tables.

• The following example shows our bank account deposit code using locks:

mysql> LOCK TABLES account WRITE;Query OK, 0 rows affected (0.00 sec)

mysql> SELECT balance FROM account WHERE number = 2;+---------+| balance |+---------+| 600 |+---------+1 row in set (0.01 sec)

mysql> UPDATE account SET balance = 1500 WHERE number = 2;Query OK, 1 row affected (0.01 sec)Rows matched: 1 Changed: 1 Warnings: 0

mysql> UNLOCK TABLES;Query OK, 0 rows affected (0.00 sec)

Page 129: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

• A call to LOCK TABLES tries to lock any tables you list so that the current thread can work with the table without interference.

• A call to UNLOCK TABLES releases any locks that this thread holds. Unlocking is straightforward. The most important thing about unlocking is that it should be done as soon as possible, to limit the impact on other threads that might be trying to access the same data.

• Locking is a more complicated issue.

• You need to request all the locks needed all at once. If we intended to access multiple tables or even multiple aliases to the one table, we would need to add them to the same call. For example, consider the following:

LOCK TABLES account WRITE, account AS a READ, othertable LOW_PRIORITY WRITE

• Calling LOCK TABLES releases all locks you currently hold, so if you attempt to collect the locks you need using multiple LOCK TABLES statements, you will release all the early ones and will only actually hold the locks requested in the final LOCK TABLES statement.

Page 130: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

• There are two main types of locks: READ and WRITE

• If you need to access a table to write, and you do not want to allow other threads to use the table at the same time, a write lock will stop any other thread from reading or writing to the table until you release it.

• A read lock is less extreme. If you only intend to read from a table, there is no harm in allowing other threads to read at the same time. A read lock bars other threads only from writing to the table during the period that your thread holds the lock.

• A write lock can also be marked as low_priority. Any system that distributes locks, needs a policy to decide who gets locks first when there are conflicting demands. MySQL generally gives write lock requests priority over read lock requests to ensure that updates to the stored data are made as soon as possible. If you do not want this behaviour, you can request a low_priority write lock. The catch is that a low_priority lock will be granted only if there are no other threads requesting read or write locks on that table. It is possible on a busy server that this might never happen.

Page 131: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

• If a thread obtains a READ lock on a table, that thread (and all other threads) can only read from the table.

• If a thread obtains a WRITE lock on a table, only the thread holding the lock can read from or write to the table. Other threads are blocked.

• When you use LOCK TABLES, you must lock all tables that you are going to use in your queries. If you are using a table multiple times in a query (with aliases), you must get a lock for each alias. While the locks obtained with a LOCK TABLES statement are in effect, you cannot access any tables that were not locked by the statement.

Page 132: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

• You will probably not often use manual control locking, but there are some reasons to do it. If you have an application that requires very high performance, but needs transaction-like behaviour only occasionally, it might be worth using a fast non-transaction-safe table type (e.g. MyISAM) and using locks to solve the transaction issue.

• Another common reason for calling LOCK TABLES is while manipulating MySQL data files directly. You might want to ensure that the disk files stay consistent and unmodified while you back them up.

• The most important thing is that you should release your locks as soon as possible because other systems and users will be kept waiting.

Page 133: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

The InnoDB Transaction Model

• To isolate transactions, InnoDB uses a fine-grained, row-level locking mechanism. This means that different transactions can run on the same table at the same time, as long as they are only reading or do not use the same rows if they are writing.

• Uncommitted changes lock other threads out of only affected rows, not a whole table. This gives InnoDB high performance, while delivering the kinds of features you expect from a modern RDBMS.

Page 134: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

ACID Compliance

ACID is an important database term that must be defined: ACID stands for Atomicity, Consistency, Isolation, and Durability. MySQL is ACID compliant when using InnoDB tables, but does not pass the “ACID” test when using MyISAM tables.

• Atomicity means that transactions are atomic and indivisible. Either all of a transaction’s changes are stored in the database, or none of them are stored. In the event of an external error, it is acceptable for those transactions affected to be completely rolled back.

Page 135: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

ACID• Consistency means that operations transform the database from one valid state to another. There are no intermediate stages where the data is inconsistent. The database should also disallow operations that violate consistency constraints. (e.g. If you are storing back accounts that relate to bank customers, it should not be possible to create an account for a customer who does not exist, and it should not be possible to delete a customer from the customer table if there are still accounts referring to them in the accounts table.)

• Isolation means that transactions do not affect each other while they are running. Each transaction should be able to view the world as though it is the only one reading and altering things. In practice this is not usually the case, but locks are used to achieve the illusion. Depending on the database and option setting, you will have different levels of isolation in practice. (Read on.)

Page 136: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

ACID• Durability means that after a transaction has been committed to the database, its effects are permanent. This is a fairly simple requirement to satisfy in a simple program, but in a complex RDBMS that uses locking and multiversioning to allow concurrent multiuser access and caching to improve performance, it is a minefield.

• Durability also implies that we should be able to recover the current state of the database in the event of a failure. If a power failure, or hard-disk crash occurs between a client sending a transaction to the database and that transaction being recorded on disk, then we should be able to combine a backup and a log to bring the database back to its pre-crash state and perhaps process transactions that had been logged but not yet executed or committed.

Page 137: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

ACIDNote: InnoDB is a multiversioned database, in that it must keep information of old versions of rows in the tablespace. This information is stored in a data structure we call a rollback segment, that allows the data structure to be rolled back if not committed.

• If you are using InnoDB tables in MySQL you are ACID compliant:

• Using the transaction syntax gives you atomicity.

• Transactions and foreign key constraints give you consistency.

• You can chose the level of isolation that transactions have from one another (read on).

• The binary log and repair tools provide durability. (Using replication, you can have a highly durable system without any single point of failure.)

Page 138: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Transaction IsolationInnoDB tables can run in four different transaction isolation levels. In order from strongest to weakest, they are:

1. Serializable.

2. Repeatable read.

3. Read committed.

4. Read uncommitted.

With these options, you have a trade-off between robustness and performance.

Page 139: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Serializable Isolation• Serializable isolation is the ideal, from a purity and robustness angle. Reads and writes on the database should appear to be happening in a sequence, with changes from a write being completely recorded before the next read starts.

• Transactions will not always have to be performed in a non-interleaved sequence to achieve this appearance because many do not interfere with each other, but in cases in which there are clashes, they will.

• This locking and waiting, combined with the overhead of predicting which combinations of transactions will interfere, makes serializable isolation the slowest isolation mode.

• To use this mode, this is the command to run:

Mysql> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

Page 140: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Repeatable Read Isolation• This is the default level for InnoDB tables. In this isolation mode, each transaction gets to work in an isolated version of the table where each row remains as it was when the transaction started. Reading a row is guaranteed to be repeatable. If you call

SELECT * FROM account WHERE number = 1;

at the start of the transaction and perform and same query later in the transaction, you will get the same result both times. You can, however, get what is called phantom reads. It is possible that another transaction which commits before yours is adding new rows to the table. If you perform the same query with a condition twice, such as

SELECT * FROM account WHERE balance > 1000;

it is possible that you will get new rows – phantom rows – the second time.

Page 141: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Repeatable Read Isolation• In practice you should very rarely see phontom reads from MySQL. InnoDB uses an algorithm called next key locking to solve this problem, as long as the column that your condition applies to is indexed. InnoDB uses row-level locking, so that when a transaction uses a row, it locks that row so that the transaction can be isolated from others. As well as locking the rows used, next key locking also locks the gaps between rows found in the index.

• Because phantom reads are addressed in this way, few systems really need to be put in serializable isolation mode.

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

Page 142: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Read Committed and Read Uncommitted• If the server is set to read committed, your transactions are no longer very isolated. If you perform a query and repeat it later in the same transaction, you will get different results the second time if another transaction has modified the data in the meantime and committed. To select this mode use:

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

• At the weakest isolation level, read uncommitted, not only are your transactions no longer isolated, consistent, and therefore not ACID compliant, but you no longer really have transactions. In this mode, it is possible for transactions to read changes that other transactions have made before the changes have been committed. This is called a dirty read. You would tolerate this only in fairly unusual circumstances, such as at a time when you know all active threads will be reading or writing, but not both.

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

Page 143: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Not PossibleNot PossibleNot PossibleSerializable

Possible (but unlikely)

Not PossibleNot PossibleRepeatable Read

PossiblePossibleNot PossibleRead Committed

PossiblePossiblePossibleRead Uncommitted

Phantom ReadNon-Repeatable Read

Dirty ReadTransaction

Isolation Levels

Transaction Isolation Level Characteristics

Page 144: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Transactions in InnoDB Tables• The power of InnoDB table types comes from using transactions, or SQL statements that are grouped together as one. A typical example of this is a bank transaction.

UPDATE person1 SET balance = balance – transfer_amount;UPDATE person2 SET balance = balance + transfer_amount;

What if something goes wrong? The system crashes after the first query is completed, but before the second is complete. Person1 will have the money removed from their account, and believes the payment has gone through, but person2 believes the payment was never made.

It is vital that either both queries are processed together, or not at all. To do this, we wrap the queries together in what is called a transaction, with BEGIN and COMMIT statements. (Note: START TRANSACTION is preferred to BEGIN as this is SQL-99 syntax.)

Page 145: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

mysql> CREATE TABLE innotest (f1 INT, f2 CHAR(10), -> INDEX (f1)) ENGINE=InnoDB;Query OK, 0 rows affected (0.02 sec)

mysql> INSERT INTO innotest(f1) VALUES(1);Query OK, 1 row affected (0.02 sec)

mysql> SELECT f1 FROM innotest;+------+| f1 |+------+| 1 |+------+1 row in set (0.00 sec)

Page 146: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

mysql> BEGIN; start transactionQuery OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO innotest(f1) VALUES(2);Query OK, 1 row affected (0.00 sec)

mysql> SELECT f1 FROM innotest;+------+| f1 |+------+| 1 || 2 | newly inserted record+------+2 rows in set (0.01 sec)

mysql> ROLLBACK; change not committed Query OK, 0 rows affected (0.01 sec)

mysql> SELECT f1 FROM innotest;+------+| f1 |+------+| 1 | table not changed+------+1 row in set (0.00 sec)

Page 147: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

mysql> BEGIN; What happens if connectionQuery OK, 0 rows affected (0.00 sec) is lost?

mysql> INSERT INTO innotest(f1) VALUES(2);Query OK, 1 row affected (0.00 sec)

mysql> SELECT f1 FROM innotest;+------+| f1 |+------+| 1 || 2 |+------+2 rows in set (0.01 sec)mysql> EXIT Exit client!!

Then log back into mysqlmysql> USE mod3;Database changedmysql> SELECT f1 FROM innotest;+------+| f1 |+------+| 1 | Lack of COMMIT before exit+------+ Table was not updated.1 row in set (0.00 sec)

Page 148: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

This time we will COMMIT themysql> BEGIN; changes before exitingQuery OK, 0 rows affected (0.02 sec)

mysql> INSERT INTO innotest(f1) VALUES(2);Query OK, 1 row affected (0.02 sec)

mysql> COMMIT;Query OK, 0 rows affected (0.00 sec)

mysql> EXIT ExitThen log back into mysql client

mysql> USE mod3;mysql> SELECT f1 FROM innotest;+------+| f1 |+------+| 1 || 2 |+------+2 rows in set (0.01 sec)

Page 149: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Consistent Reads• By default, InnoDB tables perform a consistent read. When a SELECT is performed, MySQL returns the values present in the database up until the most recently completed transaction.

• If any transactions are in progress, any UPDATE or INSERT statements will not be reflected.

• There is one exception: The open transaction itself can see the changes. These changes are then committed or rolled back.

• The following slides will demonstrate this, using two running clients, both having access to the same database and tables concurrently.

Page 150: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Client#1mysql> BEGIN; (or use START TRANSACTION;)Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO innotest (f1) VALUES (3);Query OK, 1 row affected (0.00 sec)

Will client#2 see this newly added record? NO, it won’t because it is an incomplete transaction. If the result was returned it would be considered an inconsistent read.

Client#2mysql> SELECT f1 FROM innotest;+------+| f1 |+------+| 1 || 2 |+------+2 rows in set (0.00 sec)

Page 151: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Client#1The open transaction can see the newly inserted record.mysql> SELECT f1 FROM innotest;+------+| f1 |+------+| 1 || 2 || 3 |+------+3 rows in set (0.00 sec)mysql> COMMIT; commit the change.Query OK, 0 rows affected (0.01 sec)

Client#2mysql> #w2 step 6mysql> SELECT f1 FROM innotest;+------+| f1 |+------+| 1 | Client#2 now sees the newly| 2 | created record.| 3 |+------+3 rows in set (0.00 sec)

Page 152: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Read Locks for Updating

• Consistent reads are not always what you want or need. If more than one user is trying to add a new record to the innotest table, each new record is suppose to insert a unique ascending number.

• In our example table, innotest, the f1 field is not a PRIMARY KEY or an AUTO_INCREMENT field, so there is nothing in the structure or design to prevent a duplicate from occurring.

• But you do want to ensure that a duplicate will not occur.

• To do this you could read the existing value of f1and then insert a new value, incremented by 1.

• This however, does not guarantee a unique value, as you will see in the next example:

Page 153: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Client#1mysql> BEGIN;Query OK, 0 rows affected (0.00 sec)mysql> SELECT MAX(f1) FROM innotest;+---------+| MAX(f1) |+---------+| 3 |+---------+1 row in set (0.00 sec)At the same time another user is using the same commands.Client#2mysql> BEGIN;Query OK, 0 rows affected (0.00 sec)mysql> SELECT MAX(f1) FROM innotest;+---------+| MAX(f1) |+---------+| 3 |+---------+1 row in set (0.00 sec)

Page 154: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Now, both users add a new record:Client#1mysql> INSERT INTO innotest(f1) VALUE(4);Query OK, 1 row affected (0.00 sec)mysql> SELECT f1 FROM innotest;+------+| f1 |+------+| 1 || 2 || 3 || 4 |+------+4 rows in set (0.00 sec)

Client#2mysql> INSERT INTO innotest(f1) VALUES(4);Query OK, 1 row affected (0.00 sec)mysql> SELECT f1 FROM innotest;+------+| f1 |+------+| 1 || 2 | Both clients see one additional record| 3 | but they cannot see each others | 4 | transaction. Therefore, both thought that+------+ the next available value was 4.4 rows in set (0.00 sec)

Page 155: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Now both clients commit their transactions:Client#1mysql> COMMIT;Client#2mysql> COMMIT;

Now both clients check the contents of the innotest table, and both see the same result.

Client#1 and Client#2mysql> SELECT f1 FROM innotest;+------+| f1 |+------+| 1 || 2 | The consistent read has not produced| 3 | results of 4 and 5.| 4 | The way to avoid this is with an| 4 | UPDATE LOCK on the SELECT.+------+5 rows in set (0.00 sec)

Page 156: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Read Locks for Sharing• There is another kind of read lock that does not return a value only if the value it is reading has been changed by another incomplete transaction. It only returns the latest data, but it is not part of a transaction that wants to change the value itself.

• Let’s use the f2 field created in the innotest table. Assume that the f1 field is populated first, but then only at a later stage in the transaction is a value of f2 added. When you SELECT, you want to see a record that has a value for the f1 field, but not a value for the f2 field, but you always want the latest record. In this case, you need to wait for the transaction to be finished before you return the result.

• Follow the example on the next slide:

Page 157: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Client#1mysql> BEGIN;Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO innotest(f1) VALUES(6);Query OK, 1 row affected (0.00 sec)

mysql> UPDATE innotest SET f2='Sebastian' WHERE f1=6;Query OK, 1 row affected (0.01 sec)Rows matched: 1 Changed: 1 Warnings: 0

Client#2If you do an ordinary SELECT now in Client#2, you will not get the latest value (because the previous transaction is incomplete, and InnoDB defaults to a consistent read.) However, if you do a SELECT with a LOCK IN SHARE MODE, you will not get a result until the transaction in client#1 is complete, which is preferable.

Page 158: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Running an ordinary query in Client#2 returns the following:Client#2mysql> SELECT MAX(f1) FROM innotest;+---------+| MAX(f1) |+---------+| 5 |+---------+1 row in set (0.00 sec)Still in Cliernt#2, performing the same query with a LOCK IN SHARE MODE will not deliver any results until client#2 commits.mysql> SELECT MAX(f1) FROM innotest LOCK IN SHARE MODE;

Client#1mysql> COMMIT; Complete the transaction in Client#1Query OK, 0 rows affected (0.01 sec)

Client#2 Now client#2 will return the correct resultmysql> SELECT MAX(f1) FROM innotest LOCK IN SHARE MODE;+---------+| MAX(f1) |+---------+| 6 |+---------+1 row in set (21.63 sec)

Page 159: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Automatic CommitsBy default, MySQL automatically commits all statements. See the example below:mysql> SELECT f1 FROM innotest;+------+| f1 | Client#1+------+| 1 || 2 || 3 || 4 || 5 || 6 |+------+6 rows in set (0.00 sec) Now the user in Client#2 inserts a record.mysql> INSERT INTO innotest(f1) VALUES(7); Client#2Query OK, 1 row affected (0.00 sec)mysql> SELECT f1 FROM innotest; Client#1+------+| f1 | Client#1+------+| 1 || 2 | Its immediately available in client#1| 3 || 4 || 5 || 6 || 7 |+------+7 rows in set (0.00 sec)

Page 160: GAME203 QUERIES & TRANSACTIONS. Performing Calculations in a Query mysql> SELECT first_name,surname,commission + 1 -> FROM sales_rep; +------------+----------+----------------+

Automatic CommitsWe will now set the AUTOCOMMIT to zero and investigate the resulting behaviour.The mysql> SET AUTOCOMMIT=0;Query OK, 0 rows affected (0.00 sec)

mysql> #w1 step 37mysql> INSERT INTO innotest(f1) VALUES(8);Query OK, 1 row affected (0.00 sec)

mysql> #w1 step 39mysql> COMMIT;Query OK, 0 rows affected (0.00 sec)