RIP, outofpages.com :(
users
id
first_name
last_name
active
created_at
1
Jack
Donnaghy
true
2001-03-06 12:34:56
2
Liz
Lemon
true
2001-03-08 09:43:01
3
Leo
Spaceman
false
2001-07-13 10:01:33
SELECT
users.first_name ,
users.last_name
FROM
users
WHERE
users.active = 1
ORDER BY id
ASC
LIMIT 5
accounts
id
user_id
balance
active
created_at
1
1
56485156.24
true
2001-03-06 12:34:56
2
1
153438.45
true
2001-03-08 09:43:01
3
2
23.92
true
2001-07-13 10:01:33
SELECT
accounts.id ,
accounts.balance
FROM
accounts
WHERE
accounts.active = 1
ORDER BY accounts.amount
DESC
SELECT the fields, aggregates, or other calculations
FROM, JOIN all the data required (usually far more)
WHERE the pool of data satisfies certain conditions
GROUPed BY fields to combine rows returned, HAVING certain conditions applied after being grouped
ORDERed BY field(s) and/or LIMITed to a specific number of records (starting at a position)
A list of five active users & net balance, whose net balance is less than $200, with the smallest balances first
User data & his/her net balance
SELECT users.name ,
SUM(accounts.balance) AS total
A list of five active users & net balance, whose net balance is less than $200, with the smallest balances first
User & account data
FROM users
LEFT JOIN account ON accounts.user_id = users.id
A list of five active users & net balance, whose net balance is less than $200, with the smallest balances first
Only active users
WHERE users.active = 1
A list of five active users & net balance, whose net balance is less than $200, with the smallest balances first
One row per user, and only for users with a net balance less than $200
GROUP BY users.id
HAVING total < 200
A list of five active users & net balance, whose net balance is less than $200, with the smallest balances first
Only show the five smallest net balances (in order)
ORDER BY total ASC
LIMIT 5
A list of five active users & net balance, whose net balance is less than $200, with the smallest balances first
SELECT users.name ,
SUM(account.balance) AS total
FROM users
LEFT JOIN account ON accounts.user_id = users.id
WHERE users.active = 1
GROUP BY users.id
HAVING total < 200
ORDER BY total ASC
LIMIT 5
What about the details?!
SQL itself is only a handful of building blocks.
How you use them depends entirely on the data you have, and what data you want out.
So let's look at the data...
(but remember: one license belongs to only one driver)
Records in the preceeding relevant table will be returned even if no records present in this table
Only records will be returned if each relevant table has a record
You're writing your query wrong. Flip table order and use LEFT
SELECT *
FROM a
JOIN b ON a.field = b.field
SELECT *
FROM a
LEFT JOIN
b ON a.field = b.field
WHERE b.field IS NOT NULL
If your left table is significantly larger than your right, a LEFT join will be a bit faster.
id
first_name
last_name
...
1
Jack
Donaghy
2
Liz
Lemon
id
person_id
number
expiration_dt
...
1
1
IL-C1234-56789
2015-05-05
Suppose we want to see every license
and its driver:
SELECT person.first_name ,
person.last_name ,
license.number
FROM license
LEFT JOIN person ON license.person_id = person.id
first_name
last_name
number
Jack
Donaghy
IL-C1234-56789
id
first_name
last_name
...
1
Jack
Donaghy
2
Liz
Lemon
id
person_id
number
expiration_dt
...
1
1
IL-C1234-56789
2015-05-05
1
1
TX-C5432-10987
2015-05-05
or none
or many
Suppose we want to see everyone's name
and license number:
SELECT person.first_name ,
person.last_name ,
license.number
FROM person
LEFT JOIN license ON license.person_id = person.id
first_name
last_name
number
Jack
Donaghy
IL-C1234-56789
Liz
Lemon
NULL
Jack
Donaghy
TX-C5432-10987
license
person
license
person
SELECT ...
FROM license
LEFT JOIN person ...
license
person
SELECT ...
FROM person
LEFT JOIN license ...
Is there anything we can learn from just looking at the schema?
id
first_name
last_name
...
1
Jack
Donaghy
2
Liz
Lemon
id
person_id
number
expiration_dt
...
1
1
IL-C1234-56789
2015-05-05
2
1
TX-C5432-10987
2014-05-05
The relationship between licenses and people is merely
a foreign key reference on a license record pointing to a person's primary key
person.id
license.person_id
But what's the worry? Add constraints to person_id
person_id
to NOT NULL
UNIQUE INDEX
on person_id
You really should still write your queries correctly!
(Reminder: A driver may drive many cars,
and each car can have many drivers)
id
first_name
1
Jack
2
Liz
(aka xref, cross-reference table)
person_id
car_id
1
1
1
2
1
4
id
name
1
T
2
The Homer
3
Vespa
4
H2
SELECT person.first_name ,
car.model
FROM person
LEFT JOIN pivot ON pivot.person_id = person.id
LEFT JOIN car ON pivot.car_id = car.id
first_name
model
Liz
NULL
Jack
T
Jack
The Homer
Jack
H2
SELECT person.first_name ,
car.model
FROM car
LEFT JOIN pivot ON pivot.car_id = car.id
LEFT JOIN person ON pivot.person_id = person.id
first_name
model
Jack
T
Jack
The Homer
Jack
H2
NULL
Vespa
SELECT person.first_name ,
car.model
FROM pivot
LEFT JOIN person ON pivot.person_id = person.id
LEFT JOIN car ON pivot.car_id = car.id
first_name
model
Jack
T
Jack
The Homer
Jack
H2
Suppose what makes a record unique changes...
person_id
car_id
1
1
1
2
1
2
1
4
active
...
true
true
false
true
SELECT
person.first_name ,
car.model
FROM person
LEFT JOIN pivot ON pivot.person_id = person.id
LEFT JOIN car ON pivot.car_id = car.id
first_name
model
Liz
NULL
Jack
T
Jack
The Homer
Jack
The Homer
Jack
H2
SELECT DISTINCT
person.first_name ,
car.model
FROM person
LEFT JOIN pivot ON pivot.person_id = person.id
LEFT JOIN car ON pivot.car_id = car.id
first_name
model
Liz
NULL
Jack
T
Jack
The Homer
Jack
H2
SELECT person.first_name ,
car.model
FROM person
LEFT JOIN pivot ON pivot.person_id = person.id
LEFT JOIN car ON pivot.car_id = car.id
GROUP BY person.id , car.model
first_name
model
Liz
NULL
Jack
T
Jack
The Homer
Jack
H2
SELECT person.first_name ,
car.model
FROM person
LEFT JOIN pivot ON pivot.person_id = person.id
LEFT JOIN car ON pivot.car_id = car.id
WHERE pivot.active = 1
first_name
model
Jack
T
Jack
The Homer
Jack
H2
SELECT person.first_name ,
car.model
FROM person
LEFT JOIN pivot ON pivot.person_id = person.id
AND pivot.active = 1
LEFT JOIN car ON pivot.car_id = car.id
first_name
model
Liz
NULL
Jack
T
Jack
The Homer
Jack
H2
SQL is simple -- based on only a handful of keywords.
But minor nuances yield drastic differences.
Thanks!
This presentation is available at
slid.es/petercompernolle/sql