SUBQUERIES

advertisement
SUBQUERIES
ACTIVITY 4-1
• Create a database called Subexamples
• Start a logfile called ACT4-1
• Save the subtext.txt file
– Copy the contents of the file
– Paste into MYSQL
– This will create the tables we will use for all Activities
this week
• Make sure that all tables have been created and
that there is data in each
– SERVICES, CLIENTS, BRANCHES, BRANCHES_SERVICES
List all clients with branch offices in California only
SELECT cname, bdesc, bloc FROM clients, branches
WHERE clients.cid =
branches.cid AND branches.bloc = 'CA';
+-----------------------------+------------------------+------+
| cname
| bdesc
|bloc|
+-----------------------------+--------------------------+----+
| JV Real Estate
| Corporate HQ
|CA |
| Rabbit Foods Inc
|Branch Office (West)|CA |
| Sharp Eyes Detective|Head Office
|CA|
+-----------------------------+---------------------------+----+
3 rows in set (0.00 sec)
List of all the branch offices belonging to "Rabbit Foods Inc".
You could run two SELECT statements:
mysql> SELECT cid FROM clients WHERE cname = 'Rabbit Foods Inc';
+------+
| cid |
+------+
| 104 |
+------+
1 row in set (0.17 sec)
mysql> SELECT bdesc FROM branches WHERE cid = 104;
+-----------------------------+
| bdesc
|
+-----------------------------+
| Branch Office (East) |
| Branch Office (West) |
+-----------------------------+
2 rows in set (0.17 sec)
OR run one subquery:
mysql> SELECT bdesc FROM branches WHERE
cid = (SELECT cid FROM clients
WHERE cname = 'Rabbit Foods Inc');
+-----------------------------+
| bdesc
|
+-----------------------------+
| Branch Office (East) |
| Branch Office (West) |
+-----------------------------+
2 rows in set (0.22 sec)
• A subquery makes it possible to combine two
or more queries into a single statement
• Uses the results of one query in the
conditional clause of the other
• Subqueries are usually regular SELECT
statements, and are separated from their
parent query by parentheses
• Subqueries are usually preceded by a conditional WHERE clause, which
can contain any of the following comparison and logical operators
= values are equal
<> values are unequal
<= value on left is less than or equal to value on right
>= value on left is greater than or equal to value on right
< value on left is less than value on right
> value on left is greater than value on right
BETWEEN value on left lies between values on right
NOT logical NOT
AND logical AND
OR logical OR
List of all those customers with exactly two branch
offices.
First, you need to figure out a way to obtain the
number of branch offices per customer
SELECT cid, COUNT(bid) FROM branches GROUP BY
cid;
+------+---------------+
| cid | count(bid) |
+------+---------------+
| 101 |
3|
| 103 |
3|
| 104 |
2|
| 110 |
1|
+-----+----------------+
4 rows in set (0.27 sec)
• You can nest subqueries to any depth, so long as the basic
rules above are followed.
• List the services used by Sharp Eyes Detective Agency
SELECT sname FROM services WHERE sid =
(SELECT sid FROM branches_services WHERE bid =
(SELECT bid FROM branches WHERE cid =
(SELECT cid FROM clients WHERE
cname = 'Sharp Eyes Detective Agency')));
+------------+
| sname |
+------------+
| Accounting |
+------------+
1 row in set (0.28 sec)
Then filter out those with just two offices with a
HAVING clause
SELECT cid, COUNT(bid) FROM branches GROUP
BY cid HAVING COUNT(bid) = 2;
+-----+------------+
| cid | count(bid) |
+-----+------------+
| 104 | 2 |
+-----+------------+
1 row in set (0.16 sec)
This subquery will take care of the three steps:
SELECT cname FROM clients WHERE cid =
(SELECT cid FROM branches GROUP BY cid
HAVING COUNT(bid) = 2);
+------------------------+
| cname
|
+------------------------+
| Rabbit Foods Inc |
+------------------------+
1 row in set (0.28 sec)
• The inner query is executed first - this query
takes care of grouping the branches by
customer ID and counting the number of
records (branch offices) in each group.
• Those customers which have exactly two
branch offices can easily be filtered out with a
HAVING clause
• The corresponding customer IDs are returned
to the main query, which then maps the IDs
into the customers table and returns the
corresponding customer name.
Select all those customers using the service with the maximum service
fee
SELECT cname, bdesc
FROM clients, branches, branches_services, services
WHERE services.sid = branches_services.sid
AND clients.cid = branches.cid
AND branches.bid = branches_services.bid
AND sfee = (SELECT MAX(sfee) FROM services);
+--------------------+----------------------------------------------+
| cname
| bdesc
|
+----------------+--------------------------------------------------+
| JV Real Estate | Customer Grievances Department |
+----------------+--------------------------------------------------+
1 row in set (0.01 sec)
HAVING CLAUSE
Which sites are using more than 50% of all available
services
SELECT bid FROM branches_services GROUP BY bid
HAVING COUNT(sid) > (SELECT COUNT(*) FROM
services)/2;
+--------+
| bid |
+--------+
| 1011 |
+--------+
1 row in set (0.22 sec)
Which sites are using more than 50% of all available
services and get the branch name and customer name
as well
SELECT c.cid, c.cname, b.bid, b.bdesc FROM clients AS c,
branches AS b, branches_services AS bs WHERE c.cid =
b.cid AND b.bid = bs.bid GROUP BY bs.bid HAVING
COUNT(bs.sid) > (SELECT COUNT(*) FROM services)/2;
+-----+--------------------+------+---------------------+
| cid | cname
| bid | bdesc
|
+------+-------------------+--------+-------------------+
| 101|JV Real Estate | 1011 | Corporate HQ |
+------+-------------------+--------+-------------------+
1 row in set (0.28 sec)
List all clients using all available services across their branch offices
SELECT clients.cname
FROM clients, branches, branches_services
WHERE branches.bid = branches_services.bid
AND branches.cid = clients.cid
GROUP BY clients.cid
HAVING COUNT(sid) = (SELECT COUNT(*) FROM services);
+---------------------------+
| cname
|
+---------------------------+
| JV Real Estate
|
+---------------------------+
1 row in set (0.01 sec)
IN OPERATOR
• A subquery can also return a single column of
multiple values
• HOW?
– By using the IN operator
• makes it possible to test if a particular value exists in
the result set, and perform the outer query if the test is
successful
List of all services being used by Branch ID 1031
SELECT sid FROM branches_services
WHERE bid = 1031;
+-----+
| sid |
+-----+
| 2|
| 3|
| 4|
+-----+
3 rows in set (0.16 sec)
And then:
SELECT sname FROM services WHERE sid = 2;
+-------------+
| sname |
+-------------+
| Recruitment |
+-------------+
1 row in set (0.28 sec)
SELECT sname FROM services WHERE sid = 3;
+-----------------+
| sname |
+-----------------+
| Data Management |
+-----------------+
1 row in set (0.17 sec)
SELECT sname FROM services WHERE sid = 4;
+----------------+
| sname |
+----------------+
| Administration |
+----------------+
1 row in set (0.11 sec)
Using the IN operator in a subquery is more efficient for this:
SELECT sname FROM services
WHERE sid IN
(SELECT sid FROM branches_services
WHERE bid = 1031);
+--------------------------+
| sname
|
+--------------------------+
| Recruitment
|
| Data Management |
| Administration
|
+--------------------------+
3 rows in set (0.27 sec)
List of all branches using the "Accounting" service
(service ID 1)
SELECT bdesc FROM branches
WHERE bid IN
(SELECT bid FROM branches_services
WHERE sid = 1);
+---------------------------------+
| bdesc
|
+---------------------------------+
| Corporate HQ
|
| Accounting Department |
| Branch Office (East)
|
| Branch Office (West)
|
| Head Office
|
+---------------------------------+
5 rows in set (0.17 sec)
Now add the customer name for each branch as well
SELECT cname, bdesc FROM branches, clients
WHERE branches.bid IN
(SELECT bid FROM branches_services
WHERE sid = 1)
AND clients.cid = branches.cid;
+--------------------------------------+---------------------------------+
| cname
| bdesc
|
+---------------------------------------+---------------------------------+
| JV Real Estate
| Corporate HQ
|
| JV Real Estate
| Accounting Department |
| Rabbit Foods Inc
| Branch Office (East)
|
| Rabbit Foods Inc
| Branch Office (West) |
| Sharp Eyes Detective Agency | Head Office
|
+-----------------------------+--------------------------------------------+
5 rows in set (0.16 sec)
Now just show the customer list (DISTINCT)
SELECT DISTINCT cname FROM branches, clients
WHERE branches.bid IN
(SELECT bid FROM branches_services
WHERE sid = 1)
AND clients.cid = branches.cid;
+---------------------------------------+
| cname
|
+---------------------------------------+
| JV Real Estate
|
| Rabbit Foods Inc
|
| Sharp Eyes Detective Agency |
+----------------------------------------+
3 rows in set (0.17 sec)
• Email logfile for your Activtiy 4-1 submission.
• Review your logfile as Activity 4-2 will
continue with subqueries.
Download