You are on page 1of 60

Advanced

 relational  databases

Dr.  Raúl  MAZO


Maître  de  conférences  /  PhD -­‐ Associate Professor
Learning  plan
1. Learn  how  to  manipulate  a  relational  database
a. Show,  create,  drop,  insert,  update
b. Select
2. Mastering  the  security  and  integrity  of  a  database
a. Security  schemas  
b. Integrity  (assertions  &  constraints)
3. Procedural  and  persistent  programming  (SQL/PSM)
a. Stored  procedures
b. Structures  of  control
c. Cursors  &  handlers
d. Functions
e. Triggers
f. Events
4. Transaction  processing  and  Database  recovery
5. Learn  how  to  optimise  SQL  queries
a. How  to  choose  the  most  appropriate  type  of  attributes
b. The  attributes  you  most  use  in  your  queries  should  be  indexed  with
I. Hash  tables
II. Trees
c. Rewrite  queries  to  prioritize  the  joints:  JOINT  >  IN  >  EXISTS  >  COUNT
d. Put  the  constraints  in  the  good  place
e. Remove  unnecessary  constraints,  selects  and  sorts
2
1 Learn  how  to  
manipulate  a  
relational  
3
database
1.1
Show,  create,  
drop,  insert,  
update  
4
Overview
• A relational database is a logical collection of
objects (tables, indexes, views, triggers, stored
procedures, etc.). These objects can be stored in
different locations on the disk space.
• In MySQL, an object (table, index, etc.) does not
belong to a user. So, if two users manage two
different companies, two databases have to be
created.

5
Using  a  Database
To  get  started  with  you  own  database,  first  check  which  databases  
currently  exist  on  the  server.

mysql> show databases;


+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
4 rows in set (0.03 sec)

6
Using  a  database
• To  delete  and  create  a  database:
mysql> DROP DATABASE IF EXISTS employees;
mysql> create database employees;

• To  check  the  existing  databases:


mysql> show databases;

• To  select  the  DB  to  use:


mysql> use employees;

7
Creating  a  Table
• Once  you  have  selected  a  database,  you  can  
view  all  database  tables:
mysql> show tables;
Empty set (0.02 sec)

• An  empty  set  indicates  that  there  are  no  


tables  yet.

8
Let’s  create  the  EMPLOYEE  table  
mysql> CREATE TABLE employee (
-> empid INT AUTO_INCREMENT,
-> firstname VARCHAR(30),
-> lastname VARCHAR(20),
-> deptcode CHAR(6),
-> salary NUMERIC(9, 2),
-> PRIMARY KEY(empid)
-> );

The  syntax  to  create  any  table  is


CREATE [TEMPORARY] TABLE nom_relation [IF NOT EXISTS]
(
nom_attribut TYPE_ATTRIBUT [OPTIONS]

);
Showing  tables
To  verify  that  the  table  has  been  created:
mysql> show tables;
+---------------------+
| Tables_in_employees |
+---------------------+
| employee |
+---------------------+
1 row in set (0.00 sec)

10
Describing  Tables
To  see  the  structure  of  a  table,  use  the  DESCRIBE  command  (or  desc):

mysql> describe employee;


+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| empid | int(11) | NO | PRI | NULL | auto_increment |
| firstname | varchar(30) | YES | | NULL | |
| lastname | varchar(20) | YES | | NULL | |
| deptcode | char(6) | YES | | NULL | |
| salary | decimal(9,2) | YES | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
5 rows in set (0.02 sec)

11
Deleting  a  table
To  delete  an  entire  table,  use  the  DROP  TABLE  
command:
mysql> drop table employee;
Query OK, 0 rows affected (0.02
sec)

12
Let’s  create  again  the  EMPLOYEE  table  
and  let’s  create  the  DEPARTMENT  +-----------+
table  
| Employee |
+-----------+
CREATE TABLE employee (
| empid |
empid INT AUTO_INCREMENT,
| firstname |
firstname VARCHAR(30),
| lastname |
lastname VARCHAR(20),
| deptcode |
deptcode CHAR(6),
| salary |
salary NUMERIC(9, 2),
+-----------+
PRIMARY KEY(empid));
+------------+
CREATE TABLE department ( | Department |
code CHAR(6), +------------+
| code |
name VARCHAR(30), | name |
managerid INT, | managerid# |
subdeptof CHAR(6), | subdeptof# |
PRIMARY KEY(code), +------------+
FOREIGN KEY(managerid) REFERENCES employee(empid),
FOREIGN KEY(subdeptof) REFERENCES department(code)
);
Let’s  create  again  the  EMPLOYEE  table  
and  let’s  create  the  DEPARTMENT  table  
CREATE TABLE employee (
empid INT AUTO_INCREMENT, But  ...  in  a  department  
firstname VARCHAR(30), there  are  several  
lastname VARCHAR(20), employers  and,  usually,  
deptcode CHAR(6), each  employee  belongs  to  
salary NUMERIC(9, 2), a  department!
PRIMARY KEY(empid));

CREATE TABLE department (


code CHAR(6),
name VARCHAR(30),
managerid INT,
subdeptof CHAR(6),
PRIMARY KEY(code),
FOREIGN KEY(managerid) REFERENCES employee(empid),
FOREIGN KEY(subdeptof) REFERENCES department(code)
);
+-----------+
| Employee |
ALTER TABLE employee +-----------+
| empid |
ADD | firstname |
FOREIGN KEY (deptcode) | lastname |
| deptcode# |
REFERENCES department(code); | salary |
+-----------+

Is  he  mad?  He  has  just  created  a  loop!  

He  could  have  done  it  from  the  beginning,  


couldn't  he?

How  is  he  going  to  do  to  insert  lines?


Before:
mysql> desc employee;
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| empid | int(11) | NO | PRI | NULL | auto_increment |
| firstname | varchar(30) | YES | | NULL | |
| lastname | varchar(20) | YES | | NULL | |
| deptcode | char(6) | YES | | NULL | |
| salary | decimal(9,2) | YES | | NULL | |
+-----------+--------------+------+-----+---------+----------------+

After  the  alter  table  …  add…:


mysql> desc employee;
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| empid | int(11) | NO | PRI | NULL | auto_increment |
| firstname | varchar(30) | YES | | NULL | |
| lastname | varchar(20) | YES | | NULL | |
| deptcode | char(6) | YES | MUL | NULL | |
| salary | decimal(9,2) | YES | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
5 rows in set (0.01 sec)
You  have  to  start  with  the  DEPARTMENT  table  
+------------+
| Department |
+------------+
INSERT INTO department VALUES | code |
('ADMIN', 'Administration', NULL, NULL); | name |
| managerid# |
| subdeptof# |
INSERT INTO department VALUES +------------+
('COMPTA', 'Comptabilite', NULL, 'ADMIN');

INSERT INTO department VALUES


('CONSUL', 'Consulting', NULL, 'ADMIN');

INSERT INTO department VALUES


('SINF', 'Systemes Information', NULL, 'CONSUL');
But…  managerid#  NULL?  
He  is really crazy!!
+-----------+
Then,  let’s  continue  
+------------+
| Employee |
| Department |
+-----------+
+------------+
with  the  EMPLOYEE | empid |
| firstname |
| code
| name
|
|
table
| lastname |
| managerid# |
| deptcode# |
| subdeptof# |
| salary |
+------------+
+-----------+

INSERT INTO employee


(firstname, lastname, deptcode, salary)
VALUES
('Raul', 'Mazo', 'ADMIN', 70000),
('Alberto', 'Contador', 'COMPTA', 40000),
('Pierre', 'Logiciel', 'SINF', 50000),
('Marie', 'Avis', 'CONSUL', 60000),
('Paul', 'Conseil', 'CONSUL', 30000),
('Toto', 'LeDirecteur', NULL, 65000);
+-----------+
| Employee |
+-----------+
| empid | Phew  !!!
| firstname |
Now,  I  can  finish  to  record  my  
| lastname |
| deptcode# | data  in  the  DEPARTMENT  table  !!
| salary |
+-----------+

+------------+
| Department |
+------------+
| code |
| name |
| managerid# |
| subdeptof# |
+------------+

UPDATE department SET managerid = 1 WHERE code = 'ADMIN';


UPDATE department SET managerid = 2 WHERE code = 'COMPTA';
UPDATE department SET managerid = 3 WHERE code = 'SINF';
UPDATE department SET managerid = 4 WHERE code = 'CONSUL';
Practice:  Insert  the  following  set  of  data  
and  use  select  * to  get  this  result:
+-------+-----------+-------------+----------+----------+
| empid | firstname | lastname | deptcode | salary |
+-------+-----------+-------------+----------+----------+
| 1 | Raul | Mazo | ADMIN | 70000.00 |
| 2 | Alberto | Contador | COMPTA | 40000.00 |
| 3 | Pierre | Logiciel | SINF | 50000.00 |
| 4 | Marie | Avis | CONSUL | 60000.00 |
| 5 | Paul | Conseil | CONSUL | 30000.00 |
| 6 | Toto | LeDirecteur | NULL | 65000.00 |
+-------+-----------+-------------+----------+----------+
+--------+----------------------+-----------+-----------+
| code | name | managerid | subdeptof |
+--------+----------------------+-----------+-----------+
| ADMIN | Administration | 1 | NULL |
| COMPTA | Comptabilite | 2 | ADMIN |
| CONSUL | Consulting | 4 | ADMIN |
| SINF | Systemes Information | 3 | CONSUL |
+--------+----------------------+-----------+-----------+20
Loading  sample  data  
• You  could  create  a  text  file  'employees.txt'  
containing  one  record  per  line.
• Values  must  be  separated  by  tabs,  and  
organized  in  the  order  in  which  the  columns  
were  listed  in  the  CREATE  TABLE  statement.
• Then,  load  the  data  via  the  LOAD  DATA  
command.

21
Now is your turn!

QCM  1.1

TP  1.1

22
1.2
Select  
statement
23
Format  of  an  SQL  Select
General  syntax: Simplified syntax :

SELECT  [  DISTINCT  ]  attributs SELECT  what_to_select


[  INTO  OUTFILE  fichier  ] FROM  which_table
[  FROM  relation ] WHERE  conditions_to_satisfy;
[  WHERE  condition  ]
[  GROUP  BY  attributs [  ASC  |  DESC  ]  ]
[  HAVING  condition  ]
[  ORDER  BY  attributs ]
[  LIMIT  [a,]  b  ];

E.g.:
SELECT * FROM department;
SELECT firstname, lastname
FROM employee
WHERE deptcode='consul';
24
Basic  queries
Once  you  are  logged  in,  you  can  try  some  simple  queries.  For  
example:
mysql> SELECT VERSION(), CURRENT_DATE;
+-----------+--------------+
| VERSION() | CURRENT_DATE |
+-----------+--------------+
| 5.6.25 | 2016-01-13 |
+-----------+--------------+
1 row in set (0.01 sec)

The  following  queries  are  equivalent:  

mysql> SELECT VERSION(), CURRENT_DATE;


mysql> select version(), current_date;
mysql> SeLeCt vErSiOn(), current_DATE;

25
Basic  queries
Here  is  another  query.  It  demonstrates  that  you  can  use  MySQL  
as  a  simple  calculator:  

mysql> SELECT SIN(PI()/4), (4+1)*5;


+-------------+---------+
| SIN(PI()/4) | (4+1)*5 |
+-------------+---------+
| 0.707107 | 25 |
+-------------+---------+

26
Basic  Queries
Semicolons  (multiple  statements  on  a  single  line) VS.  comas  
(multiple  columns  in  a  single  line):  

mysql> SELECT NOW(); SELECT VERSION();


+---------------------+
| NOW() |
+---------------------+
| 2004 00:15:33 |
+---------------------+

+--------------+ mysql> SELECT SIN(PI()/4), (4+1)*5;


| VERSION() | +-------------+---------+
+--------------+ | SIN(PI()/4) | (4+1)*5 |
+-------------+---------+
| 3.22.20a-log | | 0.707107 | 25 |
+--------------+ +-------------+---------+

27
Multi-­‐line  commands
MySQL  determines  where  your  statement  ends  by  
looking  for  the  terminating  semicolon,  not  by  looking  for  
the  end  of  the  input  line.

mysql> SELECT
-> USER()
-> ,
-> CURRENT_DATE;
+----------------+--------------+
| user() | current_date |
+----------------+--------------+
| root@localhost | 2016-01-13 |
+----------------+--------------+
28
Canceling  a  command
If  you  decide  you  don't  want  to  execute  a  
command  that  you  are  in  the  process  of  
entering,  cancel  it  by  typing  \c

mysql> SELECT
-> USER()
-> \c
mysql>

29
+-----------+

Examples 1  et  2 | Employee |


+-----------+
| empid |
| firstname |
1. Select  the  first  name,  last  name  and  salary  of  all   | lastname |
the  persons  enrolled  in  a  department. | deptcode# |
| salary |
Select firstname, lastname, salary +-----------+
from employee e, department d
where e.deptcode=d.code; +------------+
| Department |
+------------+
2.  Select  the  first  name,  last  name  and  salary  of  all   | code |
the  persons  in  the  'consulting'  department. | name |
| managerid# |
| subdeptof# |
Select firstname, lastname, salary +------------+
from employee e, department d
where e.deptcode=d.code and
d.name='consulting';

30
+-----------+

Example 3 | Employee |
+-----------+
| empid |
| firstname |
Select  the  first  name,  last  name  and  salary  of   | lastname |
the  employees  who  belong  to  the  consulting   | deptcode# |
department  and  they  earn  more  than  50.000  a   | salary |
year  (then  calculate  the  monthly  salary). +-----------+

+------------+
Select firstname, lastname, salary
| Department |
from employee e, department d +------------+
where e.deptcode=d.code and | code |
d.name='consulting' and salary > 50000; | name |
| managerid# |
Select salary/12 'salaire mensuel' | subdeptof# |
from employee e, department d +------------+
where e.deptcode=d.code and
d.name='consulting' and salary > 50000;

Or  salary div 12 if  we just want the  Integer part


31
+-----------+

Example 4 | Employee |
+-----------+
| empid |
| firstname |
Calculate  the  total  of  wages  paid  to  employees   | lastname |
by  department (ORDER  BY  code). | deptcode# |
| salary |
Select d.code, sum(salary) +-----------+
from employee e, department d
+------------+
where e.deptcode=d.code
| Department |
group by d.code; +------------+
| code |
You  can use  Order by  …  DESC  or  ASC  after group  by,   | name |
for  example: | managerid# |
| subdeptof# |
Select d.code, sum(salary) +------------+
from employee e, department d
where e.deptcode=d.code
group by d.code
order by d.code DESC;
32
+-----------+

Example 5   | Employee |
+-----------+
| empid |
| firstname |
Build  the  list  of  salaries  by  department. | lastname |
| deptcode# |
SELECT deptcode, salary | salary |
FROM employee e, department d +-----------+
WHERE d.code=e.deptcode +------------+
GROUP BY deptcode; | Department |
+------------+
| code |
| name |
ERROR  1055  (42000):  Expression  #2  of  SELECT   | managerid# |
list  is  not  in  GROUP  BY  clause  and  contains   | subdeptof# |
nonaggregated column  'employees.e.salary'   +------------+

which  is  not  functionally  dependent  on  columns  


in  GROUP  BY  clause;  this  is  incompatible  with  
sql_mode=only_full_group_by
33
+-----------+

Example 5   | Employee |
+-----------+
| empid |
| firstname |
Build  the  list  of  salaries  by  department. | lastname |
| deptcode# |
SELECT deptcode, salary | salary |
FROM employee e, department d +-----------+
WHERE d.code=e.deptcode +------------+
GROUP BY deptcode; | Department |
+------------+
According  to  the  documentation,  this  configuration  is   | code |
| name |
being  enabled  by  default  from  MySQL  5.7.5  because  
| managerid# |
GROUP  BY  processing  has  become  more  sophisticated   | subdeptof# |
to  include  detection  of  functional  dependencies   +------------+
(salary  is  not  functionally  dependent  on  deptcode).  It  
also  brings  MySQL  closer  to  the  best  practices  for  SQL  
language  with  the  bonus  of  removing  the  “magic”  
element  when  grouping.  Having  that,  grouping  fields  
are  no  longer  arbitrary  selected. 34
Example 5  
If  you  are  upgrading  your  database  server  and  want  to  avoid  any  possible  breaks  you  can  
disable  by  disabling  ONLY_FULL_GROUP_BY  from  your  sql_mode.

Changing  in  runtime

SET  @@GLOBAL.sql_mode =  
'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZER
O,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
A  restart  is  not  necessary,  but  a  reconnection  is.

Change  permanently

If  you  want  to  disable  it  permanently,  add/edit  the  following  in  your  my.cnf file:

sql_mode =  
"STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZER
O,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
For  this  change  a  service  restart  is  required

sudo /usr/local/mysql/support-­‐files/mysql.server restart 35


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

Example 5   | Employee |
+-----------+
| empid |
| firstname |
Build  the  list  of  salaries  by  department. | lastname |
| deptcode# |
Connect  again  to  MySQL,  charge  the  database   | salary |
and  execute  the  request  again: +-----------+

+------------+
SELECT deptcode, salary | Department |
FROM employee e, department d +------------+
WHERE d.code=e.deptcode | code |
| name |
GROUP BY deptcode; | managerid# |
+----------+----------+ | subdeptof# |
| deptcode | salary | +------------+
+----------+----------+
| ADMIN | 70000.00 |
| COMPTA | 40000.00 |
| CONSUL | 60000.00 |
| SINF | 50000.00 |
+----------+----------+ 36
+-----------+
Exemple  6 | Employee |
+-----------+
| empid |
List  the  employees  without  any  department. | firstname |
| lastname |
In  order to  do  that,  you need to: | deptcode# |
1. List  all  employees  who  have  been  registered   | salary |
at  least  once  in  a  department  (inner  query). +-----------+
2. Then,  select  the  employees  who  are  not  in   +------------+
the  list  provided  by  the  inner  query. | Department |
+------------+
select * from employee | code |
| name |
where empid not in | managerid# |
(select e.empid | subdeptof# |
from employee e, department d +------------+
where e.deptcode=d.code);

But  there  are  other  requests  somewhat  more  difficult  to  express  in  SQL,  
for  example  when  it  comes  to  finding  the  elements  that  have  ALWAYS  ...
37
+-----------+
Exemple  7 | Employee |
+-----------+
| empid |
Queries  to  find  elements  that  have  (always or  taken   | firstname |
every)  … | lastname |
You  have  to  implement a  division  (relational algebra)! | deptcode# |
| salary |
The  division  can  express  universal  quantification  (∀). +-----------+

Example  of  a  query  for  which  the  division  is  useful:   +------------+
"List  the  employees  who  are  hired  in  all  departments" |+------------+
Department |

| code |
select * from employee | name |
| managerid# |
where empid not exists | subdeptof# |
(select e.empid +------------+
from employee e, department d
where e.deptcode=d.code);

Here  (next  slide)  is  a  more  complex  example  in  a  database  in  which  it  is  
possible  to  add  constraints  to  the  division  : 38
Division  query
Student  (Id,  Name)
Course  (CrsCode,  Dept)
Transcript  (StudId,  CrsCode,  Grade)
Query:  Find  the  names  of  students  who  have  taken  every  
course  offered  by  the  CS  department.

Student Course Transcript


1234 Adam
2345 Bill CS101 CS 1234 CS101 2.5
3456 Cathy 2345 CS234 3.5
4567 Didi CS234 CS 1234 CS234 4.0
5678 Eva

Result Adam
39
Division  query  in  SQL
Student  (Id,  Name)
Course  (CrsCode,  CrsName,  Dept)
Transcript  (StudId,  CrsCode,  Semester,  Grade)

Query:  Find  the  names  of  students  who  have  


taken  every  course  offered  by  the  CS  department.
SELECT  Name
FROM   Student  
WHERE  ? Student  has  taken  ALL
the  CS  courses

40
Division  Query  in  SQL
Student  (Id,  Name)
Course  (CrsCode,  CrsName,  Dept)
Transcript  (StudId,  CrsCode,  Semester,  Grade)

Query:  Find  the  names  of  students  who  have  


taken  every  course  offered  by  the  CS  department.
SELECT  Name
FROM   Student
WHERE  EXISTS  (SELECT  *
FROM  Transcript,  Course
WHERE  Transcript.StudId  =  Student.Id
AND  Transcript.CrsCode  =  Course.CrsCode
AND  Course.Dept  =  ‘CS’)
This  will  return  names  of  students  who  have  taken  at  least  1  CS  course
41
Division  Query  in  SQL
Student  (Id,  Name)
Course  (CrsCode,  CrsName,  Dept)
Transcript  (StudId,  CrsCode,  Semester,  Grade)

Query:  Find  the  names  of  students  who  have  


taken  every  course  offered  by  the  CS  department.
SELECT  Name
FROM   Student   Student  has  taken  ALL
WHERE  ? the  CS  courses

42
Division  Query  in  SQL
Student  (Id,  Name)
Course  (CrsCode,  CrsName,  Dept)
Transcript  (StudId,  CrsCode,  Semester,  Grade)

Query:  Find  the  names  of  students  who  have  


taken  every  course  offered  by  the  CS  department.
SELECT  Name
FROM        Student  
WHERE  ( Equivalent  to  saying  “there  
? are  no  CS  courses  the  
student  has  not  taken”
)

43
Division  Query  in  SQL
Student  (Id,  Name)
Course  (CrsCode,  CrsName,  Dept)
Transcript  (StudId,  CrsCode,  Semester,  Grade)

Query:  Find  the  names  of  students  who  have  


taken  every  course  offered  by  the  CS  department.
SELECT  Name
FROM        Student  
WHERE  NOT  EXISTS  (
A  CS  course  the  
? student  has  not  taken
)

44
Division  Query  in  SQL
Student  (Id,  Name)
Course  (CrsCode,  CrsName,  Dept)
Transcript  (StudId,  CrsCode,  Semester,  Grade)

Query:  Find  the  names  of  students  who  have  


taken  every  course  offered  by  the  CS  department.
SELECT  Name
FROM   Student  
WHERE  NOT  EXISTS  (
SELECT  *  FROM  Course
WHERE  Dept =  ‘CS’ Student  has  not  taken  
AND  ? the  CS  course
)
(Student,  course)  combination  does  not  exist  in  Transcript
45
Division  Query  in  SQL
Student  (Id,  Name)
Course  (CrsCode,  CrsName,  Dept)
Transcript  (StudId,  CrsCode,  Semester,  Grade)

Query:  Find  the  names  of  students  who  have  taken  


every  course  offered  by  the  CS  department.
SELECT  Name
FROM   Student  
WHERE  NOT  EXISTS  (
SELECT  *  FROM  Course
WHERE  Dept =  ‘CS’
AND  NOT  EXISTS  (
SELECT  *  FROM  Transcript
WHERE  Transcript.StudId =  Student.Id
AND  Transcript.Crscode =  Course.Crscode
)  )

46
Another  possible  solution
Student  (Id,  Name)
Course  (CrsCode,  CrsName,  Dept)
Transcript  (StudId,  CrsCode,  Semester,  Grade)

Query:  Find  the  names  of  students  who  have  


taken  every  course  offered  by  the  CS  department.
SELECT  Name
FROM   Student  
WHERE  NOT  EXISTS  (
SELECT  *  FROM  Course
WHERE  Dept =  ‘CS’
AND  CrsCode NOT  IN  (
SELECT  CrsCode FROM  Transcript
WHERE  Transcript.StudId =  Student.Id)
)
47
Available functions
• See  the  MySQL  manual  for  a  detailed  list  of  all  functions  available  in  your  
MySQL  server  version.
• You  can  add  these  functions  to  your  queries  in  a  SELECT,  WHERE,  GROUP  
BY  or  HAVING.
You  can  use:
• Parenthesis  (  )
• Arithmetic  operators  (+,  -­‐,  *,  /,  %)
• The  logical  operators  that  return  0 (false)  or  1 (true)  (AND,  OR,  NOT,  
BETWEEN,  IN)
• Relational  operators  (<,  <=,  =,  >,  >=,  <>)
• Operators  and  functions  can  be  mixed  to  give  very  complex  expressions

Exercise  8:  Retrieve  the  first  and  last  names  of  employees  in  department  
'CONSUL'  whose  salary  is  between  €30,000  and  €40,000.
SELECT Fname, Lname
FROM EMPLOYEE
WHERE (Salary BETWEEN 30000 AND 40000) AND deptcode = 'CONSUL';
48
String  comparison functions
• The  keyword  LIKE  is  used  to  compare  two  strings  (case  
insensitive).
• Character '%' is special and  means:  0  or  several characters.
• Character '_' is special and  means:  only 1  seul  character,  
whatever it is.

• If  you want to  use  these characters mentionned above but  


without their specific function,  insert  a  backslash '\‘  
before the  character.
For  example,  to  list  the  departments  whose  code  begins  with  
the  string  '_CO',  use  :
SELECT  *
FROM  department
WHERE  code  LIKE '\_CO%'
49
Mathematical functions
Fonction Description
ABS(x) Absolute value  of  X
SIGN(x) X  sign,  returns  -­1,  0  or  1
FLOOR(x) Rounds  down  to  nearest  integer
CEILING(x) Roundes up  to  the  nearest  integer
ROUND(x) Rounds  to  the  nearest  integer
EXP(x),  LOG(x),  SIN(x),   Very basic  mathematical functions…!
COS(x),  TAN(x),  PI()  
POW(x,y) Returns the  value  of  X  to  the  power  of  Y
RAND(),  RAND(x) Returns  random  numbers  between  0  and  1.0.  
If  x  is specified,  between 0  et  X
TRUNCATE(x,y) Truncates the  number X to  an  
optional and decimal  places

To  go  forward…
Think and  implement an  
example for  each function!
50
String  functions
Fonction Description
TRIM(x) Removes  spaces  at  the  beginning  and  end  of  a  string
LOWER(x) Converts to  lowercase
UPPER(x) Converts to  uppercase
LONGUEUR(x) Returns  the  size  of  the  chain
LOCATE(x,y) Returns the  position  of  the  last  occurrence  of  x  in  y.  
Returns  0  if  x  is  not  found  in  y
CONCAT(x,y,…) Concatenates the  arguments
SUBSTRING(s,i,n) Returns  the  last  n  characters  of  s  starting  from  the  
position  i
SOUNDEX(x) Returns  a  phonetic  representation  of  x

To  go  forward…
Think and  implement an  
example for  each function!
51
Date  and  time  functions
Fonction Description
NOW() Returns the  current date  and  time.
TO_DAYS(x) Return  the  date  converted to  days since 1st  
January 1970
DAYOFWEEK(x) Returns the  day of  the  week of  the  X  date.  
Index  starting by  1  (1=Sunday,  2=Monday…)
DAYOFMONTH(x) Returns the  day of  month (from 1  to  31)
DAYOFYEAR(x) Returns the  day of  year (from 1  to  366)
SECOND(x),  MINUTE(x),   Returns seconds,  minutes,  hours,  month,  year  
HOUR(x),  MONTH(x),   and  week  date.
YEAR(x),  WEEK(x)  

To  go  forward…
Think and  implement an  
example for  each function!

52
Functions  to  use  in  the  GROUP  BY
Fonction Description
COUNT([DISTINCT]x,y,…) Count  of  tuples  of  the  result  by  projecting  on  
the  specified  attribute(s)  (or  all  with  '*').  The  
DISTINCT  option  eliminates  duplication.
MIN(x),  MAX(x),  AVG(x),   Respectively  calculates  the  minimum,  
SUM(x) maximum,  average  and  sum  of  X  attribute  
values.

To  go  forward…
Think and  implement an  
example for  each function!

53
Regular  Expression  Matching
• The  other  type  of  pattern  matching  provided  
by  MySQL  uses  extended  regular  expressions.

• When  you  test  for  a  match  for  this  type  of  


pattern,  use  the  REGEXP  and  NOT  REGEXP  
operators  (or  RLIKE  and  NOT  RLIKE,  which  are  
synonyms).  

54
Regular  Expressions
Some  characteristics  of  extended  regular  expressions:

.  matches  any  single  character.  

A  character  class  [...]  matches  any  character  within  the  brackets.  


For  example,  [abc]  matches  a,  b,  or  c.  To  name  a  range  of  
characters,  use  a  dash.  [a-­‐z]  matches  any  lowercase  letter,  
whereas  [0-­‐9]  matches  any  digit.  

*  matches  zero  or  more  instances  of  the  thing  preceding  it.  For  
example,  x*  matches  any  number  of  x  characters,  [0-­‐9]*  matches  
any  number  of  digits,  and  .*  matches  any  number  of  anything.  

To  anchor  a  pattern  so  that  it  must  match  the  beginning  or  end  of  
the  value  being  tested,  use  ^  at  the  beginning  or  $  at  the  end  of  
the  pattern.  
55
+-----------+
| Employee |
Example  9 +-----------+
| empid |
| firstname |
| lastname |
To  find  names  (firstnames)  beginning  with  R,  use  ^ | deptcode# |
| salary |
+-----------+
mysql> SELECT * FROM employee
WHERE firstname REGEXP '^r';
+------------+
| Department |
+-------+-----------+----------+----------+----------+ +------------+
| empid | firstname | lastname | deptcode | salary | | code |
+-------+-----------+----------+----------+----------+ | name |
| 1 | Raul | Mazo | ADMIN | 70000.00 | | managerid# |
+-------+-----------+----------+----------+----------+ | subdeptof# |
1 row in set (0.00 sec)
+------------+

56
+-----------+

Example 10 | Employee |
+-----------+
| empid |
Build the  list of  person(s)  earning the  highest wages. | firstname |
| lastname |
You  can think it would be:   | deptcode# |
select empid, max(salary) from employee; | salary |
+-----------+
But  if  you insert  another tuple with the  max wage (obtained),  you
see that it does not  work: +------------+
INSERT INTO employee (firstname,lastname, | Department |
deptcode, salary) VALUES ('Ivan', 'Perez', +------------+
'ADMIN', 70000); | code |
| name |
So,  use  this  syntax:   | managerid# |
select empid, firstname, salary from employee | subdeptof# |
where salary=(select max(salary) from +------------+
employee);

You  can also use  LIMIT:  


select empid, firstname, salary from employee
oderr by salary desc limit 1;
57
+-----------+
Example 11 | Employee |
+-----------+
| empid |
Find  the  names  of  employees  who  earn  more  than  (all)   | firstname |
| lastname |
their  managers ? | deptcode# |
Here  are  two  possibilities.  They  seem  similar  but  beware!  One  of  it | salary |
(which one?)  works only for  specific cases.  Why? +-----------+

Select e.firstname, e.lastname


FROM employee e, employee m, department d
WHERE e.deptcode=d.code AND
d.managerid=m.empid AND e.salary > +------------+
m.salary; | Department |
+------------+
SELECT e.firstname, e.lastname | code |
FROM employee e WHERE e.salary > ALL | name |
| managerid# |
(SELECT m.salary FROM employee m, | subdeptof# |
department d WHERE e.deptcode=d.code AND +------------+
d.managerid=m.empid);
58
+-----------+

Example 12 | Employee |
+-----------+
| empid |
| firstname |
How  to  find  the  names  of  employees  who  are   | lastname |
not  associated  with  any  department? | deptcode# |
| salary |
There  are  several  possibilities,  for  example: +-----------+

SELECT * FROM EMPLOYEE WHERE +------------+


deptcode IS NULL; | Department |
+------------+
| code |
select * from employee e where not | name |
exists (select 1 from department d | managerid# |
where e.deptcode=d.code); | subdeptof# |
+------------+
select * from employee e where 0 =
(select count(*) from department
d where e.deptcode=d.code);

Classify these queries from the  most to  the  least  efficient.  Why this choice?
59
Now is your turn!

QCM  1.2

TP  1.2

60

You might also like