On Fri, 13 Aug 2004 04:02:13 GMT, "Xenophobe" <xe*******@planetx.com> wrote:
There are still two tables, ServiceTypes (table1) and ServiceCompanies
(table2):
Table: ServiceTypes (table1)
Columns: ServiceTypeID, ServiceTypeName
Table: ServiceCompanies (table2)
Columns: ServiceTypeID, CompanyID
ServiceTypeID, ServiceTypeName
1, Plumbing
2, Electrical
3, Flooring
4, Drywall
5, Landscaping
ServiceTypeID, CompanyID
1, 1
2, 1
3, 1
1, 2
2, 2
So here's my challenge. I would like to return a recordset of services that
are NOT currently associated with a company. This would allow them to add
any additional services that aren't already defined.
I have played with many variations of the following query and read the docs,
but without success.
SELECT ST.ServiceTypeID FROM ServiceTypes ST
LEFT JOIN ServiceCompanies SC ON ST.ServiceTypeID = SC.ServiceTypeID
WHERE SC.ServiceTypeID IS NULL and SC.CompanyID = ?
No matter what, I always get zero results. The reason for this seems to be
that the query finds other references to ServiceTypeID in ServiceCompanies
and is ignoring the CompanyID specific portion of the WHERE clause.
You're very close, but your problem is where you've put one of the conditions.
Solution first, then I'll have a go at explaining it:
mysql> select * from ServiceTypes;
+---------------+-----------------+
| ServiceTypeID | ServiceTypeName |
+---------------+-----------------+
| 1 | Plumbing |
| 2 | Electrical |
| 3 | Flooring |
| 4 | Drywall |
| 5 | Landscaping |
+---------------+-----------------+
5 rows in set (0.00 sec)
mysql> select * from ServiceCompanies;
+---------------+-----------+
| ServiceTypeID | CompanyID |
+---------------+-----------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 1 | 2 |
| 2 | 2 |
| 4 | 2 |
+---------------+-----------+
6 rows in set (0.00 sec)
mysql> SELECT ST.ServiceTypeID
-> FROM ServiceTypes ST
-> LEFT JOIN ServiceCompanies SC
-> ON (ST.ServiceTypeID = SC.ServiceTypeID
-> AND SC.CompanyID = 1)
-> WHERE SC.ServiceTypeID IS NULL;
+---------------+
| ServiceTypeID |
+---------------+
| 4 |
| 5 |
+---------------+
2 rows in set (0.00 sec)
Why does the condition need to be inside the LEFT JOIN join condition? Well,
you're looking for rows that are for CompanyID=1 that aren't in ServiceTypes,
so having the condition as an ordinary WHERE clause will never match - the rows
aren't there. Consider this, without the IS NULL test:
mysql> SELECT ST.ServiceTypeID,
-> SC.ServiceTypeID,
-> SC.CompanyID
-> FROM ServiceTypes ST
-> LEFT JOIN ServiceCompanies SC
-> ON (ST.ServiceTypeID = SC.ServiceTypeID)
-> WHERE SC.CompanyID = 1;
+---------------+---------------+-----------+
| ServiceTypeID | ServiceTypeID | CompanyID |
+---------------+---------------+-----------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 3 | 1 |
+---------------+---------------+-----------+
3 rows in set (0.00 sec)
Its filtered it down to those services that CompanyID=1 does - the WHERE
clause is applied after the outer join, and now you don't have the rows that
you wanted to pick, as the WHERE has filtered off the rows the outer join adds.
Putting the CompanyID as part of the outer join condition gives you:
mysql> SELECT ST.ServiceTypeID,
-> SC.ServiceTypeID,
-> SC.CompanyID
-> FROM ServiceTypes ST
-> LEFT JOIN ServiceCompanies SC
-> ON (ST.ServiceTypeID = SC.ServiceTypeID
-> AND SC.CompanyID = 1);
+---------------+---------------+-----------+
| ServiceTypeID | ServiceTypeID | CompanyID |
+---------------+---------------+-----------+
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 3 | 1 |
| 4 | NULL | NULL |
| 5 | NULL | NULL |
+---------------+---------------+-----------+
5 rows in set (0.01 sec)
Then you just filter off those with one of the SC columns that are null,
ending up with the solution above.
--
Andy Hassall / <an**@andyh.co.uk> / <http://www.andyh.co.uk>
<http://www.andyhsoftware.co.uk/space> Space: disk usage analysis tool