Joinable tables
Manual joins are perfectly fine, but how can we define the tables to be joinable without manually specifying on which columns to join? The answer is foreign keys.
Foreign key definition
- A column that is a reference to the key of another table, i.e.
Product.manufacturer <- Company.cname - Gives information and enforces constraints
Join explained by a Cartesian product
SELECT *
FROM Department, FacultyYields the cartesian product of two tables, i.e.
SELECT *
FROM Department, Faculty
WHERE dfaculty=fnameYields the cartesian product with some constraints, i.e.
Unintuitive joins
SELECT R.A
FROM R, S, T
WHERE R.A=S.A OR R.A=T.ASeemingly, we’re looking for
Disambiguating attributes
Sometimes two relations have the same name for one or more columns. In this case, we’re supposed to use the relation name to disambiguate the attribute, i.e. Person.address, Company.address instead of just address, address
Renaming, aka AS definition
Question - find all stores that sold at least one product that BestBuy store also sold?
Proposed query:
SELECT DISTINCT store
FROM Purchase
WHERE store = 'BestBuy'This query is obviously wrong, as it only returns BestBuy itself
We encounter a problem - we have to match two or more different rows on the same column in the same table
The solution is a self-join!
SELECT DISTINCT store
FROM Purchase, Purchase
WHERE product = product
AND store = 'BestBuy'The problem is that all columns are now ambiguous
The solution to this problem is aliasing, or AS
SELECT DISTINCT x.store
FROM Purchase AS x, Purchase AS y
WHERE x.product = y.product
AND y.store = 'BestBuy'And now the query actually works. The only question is - do we want to return BestBuy itself or not?
SELECT DISTINCT x.store
FROM Purchase AS x, Purchase AS y
WHERE x.product = y.product
AND y.store = 'BestBuy'
AND x.store <> 'BestBuy'It is also possible to rename attributes (columns) in the SELECT resulting table
Scope of the created “variable” is the entire query (for now)
Exercises
- Product(pname, price, category, manufacturer)
- Purchase(buyer, seller, store, product)
- Company(cname, stockPrice, country)
- Person(pername, phoneNumber, city)
Ex1
Find all people who bought telephony products
SELECT pur.buyer
FROM Purchase AS pur, Product AS pr
WHERE pur.product = pr.pname
AND pr.category = 'telephony'Ex2
Find names of people who bought American products
SELECT DISTINCT pur.buyer
FROM Purchase AS pur, Product AS pr, Company AS c
WHERE pur.product = pr.pname AND pr.manufacturer = c.cname
AND c.country = 'USA'Ex3
Find names of people who bought American products and they live in Seattle
SELECT DISTINCT per.pername
FROM Person AS per, Purchase AS pur, Product AS pr,
Company AS c
WHERE per.pername = pur.buyer AND pur.product = pr.pname
AND pr.manufacturer = c.cname
AND c.country = 'USA'
AND per.city = 'Seattle'Ex4
Find people who have both bought and sold something
SELECT DISTINCT buy.buyer
FROM Purchase AS buy, Purchase AS sell
WHERE buy.buyer = sell.sellerEx5
Find a purchase involving a person from Seattle and a person from Tokyo
SELECT DISTINCT buy.buyer AS 'buyer', buy.seller AS 'seller',
buy.store AS 'store', buy.product AS 'product'
FROM Purchase AS pur, Person AS buy, Person AS sell
WHERE pur.buyer = buy.pername AND pur.seller = sell.pername
AND (
(buy.city = 'Seattle' AND sell.city = 'Tokyo')
OR (buy.city = 'Tokyo' AND sell.city = 'Seattle')
)Bag operations
Union definition
Union of two result tables with equal columns(!)
UNION returns distinct entries by default, use UNION ALL to keep them
Example, select all people who live in Seattle or bought something from BestBuy
(SELECT name
FROM Person
WHERE city='Seattle')
UNION
(SELECT buyer as name
FROM Purchase
WHERE store='BestBuy')Except definition
Difference of two result tables with equal columns(!)
EXCEPT returns distinct entries
Example, select all people who live in Seattle and didn’t buy anything from BestBuy
(SELECT name
FROM Person
WHERE city='Seattle')
EXCEPT
(SELECT buyer as name
FROM Purchase
WHERE store='BestBuy')Intersect definition
Intersection of two result tables with equal columns(!)
INTERSECT returns distinct entries
Example, select all people who live in Seattle and bought something from BestBuy
(SELECT name
FROM Person
WHERE city='Seattle')
INTERSECT
(SELECT buyer as name
FROM Purchase
WHERE store='BestBuy')Subqueries definition
One-row one-column
Subquery can be treated as an atomic value if and only if it returns a one-row and one-column result
SELECT Purchase.product
FROM Purchase
WHERE Purchase.buyer = (SELECT name
FROM Person
WHERE ID = '123456789')In definition
Checking if a value exists in the set Subquery can return any number of results, but no error
SELECT Purchase.product
FROM Purchase
WHERE Purchase.buyer IN
(SELECT name
FROM Person
WHERE city='Seattle')Subquery can also return multiple columns
SELECT Purchase.product
FROM Purchase
WHERE (Purchase.buyer, Purchase.store) IN
(SELECT name, city
FROM Person)All definition
Quantifying over a subquery, i.e.
SELECT Purchase.product
FROM Purchase
WHERE Purchase.price >= ALL
(SELECT price
FROM Purchase)Any definition
Quantifying over a subquery, i.e.
SELECT Purchase.product
FROM Purchase
WHERE Purchase.price > ANY
(SELECT price
FROM Purchase)Exists definition
Quantifying over a subquery, i.e. subquery is non-empty (or empty)
SELECT Purchase.product
FROM Purchase
WHERE EXISTS
(SELECT *
FROM Person
WHERE store=city);
SELECT Purchase.product
FROM Purchase
WHERE NOT EXISTS
(SELECT *
FROM Person
WHERE store=city);Usage
Note that these clauses can be used almost everywhere, not just as part of a
WHEREclause More specifically, inWHERE,FROM,SELECTandHAVING
Aggregation definition
When added to a simple SELECT-FROM-WHERE query:
- Computed over the result set
- returns a single value (one row) SQL supports the following:
SUM,MIN,MAX,AVG- single columnCOUNT- any number of columns, counts only rowsCOUNT(DISTINCT ...)counts only rows, distinct by columns in...