In a one-to-many relationship, a join condition may make some rows invisible in the output from a query. Here's a simple way to make them visible again using an OUTER JOIN.
Sometimes a JOIN seems to lose things that should be there. Surprisingly, this is normal and desired behavior, and fortunately, there's a way to get exactly what you are looking for. Suppose you have a database of customers, shown in Table 5-4, and invoices, shown in Table 5-5. You need to write a query to return the number of invoices in the database for each customer. Some customers haven't ordered anything yet, and for them the count should be 0.
ID | Name |
---|---|
1 | Betty |
2 | Robert |
3 | Janette |
Invoiceno | Whn | Custid | Cost |
---|---|---|---|
1 | 2006-11-01 | 1 | 100 |
2 | 2006-11-05 | 1 | 500 |
3 | 2006-11-11 | 3 | 200 |
Consider the following query:
SELECT name,COUNT(*) FROM customer JOIN invoice on (id=custid) GROUP BY name
Here are the results:
Name COUNT(*) ------------------------ Betty 2 Janette 1
The JOIN has restricted the result to cases where there is at least one entry for a customer in invoice.
If you want to get a count of 0 for Robert you need a LEFT OUTER JOIN so that every row of the table on the left (customer) is included:
SELECT name,count(*) FROM customer LEFT JOIN invoice on (id=custid)
Now, Robert is included even though he has no invoices:
Name count(*) ------------------------ Betty 2 Robert 0 Janette 1
You can also solve this problem by using a UNION, and writing a second query that returns 0 for customers who are not in invoice:
SELECT name,count(*) FROM customer JOIN invoice ON (id=custid) UNION SELECT name,0 FROM customer WHERE id NOT IN (SELECT custid FROM invoice)
SQL Fundamentals
Joins, Unions, and Views
Text Handling
Date Handling
Number Crunching
Online Applications
Organizing Data
Storing Small Amounts of Data
Locking and Performance
Reporting
Users and Administration
Wider Access
Index