Hi Josh, As I mentioned elsewhere, you're very welcome, happy to help.
To answer your next questions as best I can (if I make any errors I'd be grateful if someone else on the list would highlight them): Let's imagine you have two tables, 1 table contains employees, the other table contains the project to which each employee is currently assigned (Note, this is not necessarily great database design, but it should serve as an adequate illustration). In the real world, of course, not every employee is currently assigned to a project, and not every project has yet been assigned to an employee. CREATE TABLE `tblemployees` (empid INT NOT NULL AUTO_INCREMENT, empname VARCHAR(50) NOT NULL DEFAULT '', empdetails VARCHAR(50) NOT NULL DEFAULT '', PRIMARY KEY (`empid`)) TYPE=MYISAM ROW_FORMAT=DEFAULT; CREATE TABLE `tblprojects` (projid INT NOT NULL AUTO_INCREMENT, empid INT NULL, projname VARCHAR(50) NOT NULL DEFAULT '', PRIMARY KEY (`projid`)) TYPE=MYISAM ROW_FORMAT=DEFAULT; INSERT INTO tblemployees (empname, empdetails) VALUES ('employee1', 'employee details1'); INSERT INTO tblemployees (empname, empdetails) VALUES ('employee2', 'employee details2'); INSERT INTO tblemployees (empname, empdetails) VALUES ('employee3', 'employee details3'); INSERT INTO tblemployees (empname, empdetails) VALUES ('employee4', 'employee details4'); INSERT INTO tblprojects (empid, projname) VALUES (1, 'project1'); INSERT INTO tblprojects (empid, projname) VALUES (NULL, 'project2'); INSERT INTO tblprojects (empid, projname) VALUES (2, 'project3'); INSERT INTO tblprojects (empid, projname) VALUES (4, 'project4'); So, if we wanted to do something relatively simple such as retrieve a recordset that reflects those employees who have been assigned to a project, and to which project they have been assigned, we would use an INNER JOIN: SELECT te.empname, te.empdetails, tp.projname FROM tblemployees te INNER JOIN tblprojects tp ON te.empid = tp.empid; This returns a recordset that looks like: "employee1","employee details1","project1" "employee2","employee details2","project3" "employee4","employee details4","project4" (Another way of retrieving the same recordset would be: SELECT te.empname, te.empdetails, tp.projname FROM tblemployees te, tblprojects tp WHERE te.empid=tp.empid;) INNER JOINs only return records from tables where associated records can be found in both. Now, we can see from the above recordset that employee1 is assigned to project1, employee2 is assigned to project3 and employee4 is assigned to project4. This recordset doesn't communicate anything about employee3 or project2, because the INNER JOIN excludes them for not having a matching record in the other table. Because we're dealing with a very small and very straightforward scenario, however, we can probably work out under our own steam just by looking at the above recordset that employee3 mustn't be currently assigned to a project and project2 hasn't been assigned to an employee. However, in a more complex scenario we might be mistakenly _assuming_ employee3 and project2 actually exist in our tables at all! So that there's no potential for confusion, you can use, for example, a LEFT JOIN to reflect all of the records in the tblemployees table and only those records from tblprojects that are currently assigned to an employee. I.E.: SELECT te.empname, te.empdetails, tp.projname FROM tblemployees te LEFT JOIN tblprojects tp ON te.empid = tp.empid; "employee1","employee details1","project1" "employee2","employee details2","project3" "employee3","employee details3",NULL "employee4","employee details4","project4" Here there can be no confusion -- employee3 does exist, but isn't assigned to a project, as indicated by the NULL in the [projname] column. Project2 is not listed in this recordset because the LEFT JOIN in this example returns all of the records from tblemployees, but only the matching records from tblprojects. Similarly, we can return all of the projects and the details of the employees that have been assigned to them, where they have been assigned. To do this, change the syntax from a LEFT JOIN to a RIGHT JOIN: SELECT te.empname, te.empdetails, tp.projname FROM tblemployees te RIGHT JOIN tblprojects tp ON te.empid = tp.empid; "employee1","employee details1","project1" NULL,NULL,"project2" "employee2","employee details2","project3" "employee4","employee details4","project4" Here we see that project2 does exist, but no employee has yet been assigned to it, as idicated by the NULLs in the [empname] and [empdetails] columns. Employee3 is not listed in this recordset because the RIGHT JOIN in this example returns all of the records from tblprojects, but only the matching records from tblemployees. You could, of course, simply maintain the LEFT JOIN syntax and change the order of the tables in the FROM clause, thus: SELECT te.empname, te.empdetails, tp.projname FROM tblprojects tp LEFT JOIN tblemployees te ON te.empid = tp.empid; By reversing the order of the tables the LEFT JOIN immediately above returns exactly the same recordset as the RIGHT JOIN example above it. So, the 'direction' of the join indicates which side of the tables listed in the FROM clause will return all of their rows, and which side will only return the data matched by the ON clause (and which can then usually be further qualified / restrained by WHERE clauses). In theory, it should be possible to retrieve a recordset that combines the LEFT JOIN and RIGHT JOIN results from our examples above in a single recordset. This would probably look something like: NULL,NULL,"project2" "employee1","employee details1","project1" "employee2","employee details2","project3" "employee3","employee details3",NULL "employee4","employee details4","project4" This is usually performed by a FULL JOIN, but I am under the impression that MySQL has yet to implement FULL JOINs (certainly, I can't get them to work on ver 3.23.53 and the documentation for my version indicates FULL JOINs are expected in ver 4.0 or 4.1). Now, to go back to your original question, the people / events / attendance example employed both a LEFT JOIN and a RIGHT JOIN because the attendance table was acting as an intermediary between the people and events tables. From my Microsoft Acess background, I would call this a 'FIND UNMATCHED' query, although instead of finding the records in one table that aren't reflected in another [1], we're finding and combining the records from two tables that aren't associated with each other in a third. I personally can't think of a way of representing the same query you have developed but only using LEFT JOINs. I'm not in a position to say it can't be done, but I certainly can't think of a way to do it. All the best, M Wells [1] As a simple example of a 'find unmatched' query, if we had a table that contained a record for each of the files on your computer and a table of all of the files from your computer that you've backed up onto a CD, then finding the records in your [allfiles] table that are unmatched (i.e. don't exist) in your [backeduptocd] table should equate to a list of all of the files on your computer that have yet to be backed up to CD -----Original Message----- From: Josh L Bernardini [mailto:[EMAIL PROTECTED]] Sent: Thursday, 23 January 2003 5:24 AM To: [EMAIL PROTECTED] Subject: solution for opposite of this join / join from this subselect thanks to brent, bob and M wells for their contributions to this solution and to m especially who seems to have put in a lot of time and nailed it. This query returns a list of people not attending a particular event, given an events table, a people table, and a many-many epeople table between them. You can modify the where clause to show all the people attending a particular event, all the events a person isn't/is attending - most of what you might need in most many - many relationships. But I still haven't figured out the importance of left joins vs. right joins. can anyone explain why this statement requires a right join to work? could it be rewritten to use a left join? mysql> SELECT lastname, firstname, title, event -> FROM people p -> LEFT JOIN epeople ep on p.id = ep.pid -> right join events e ON e.id = ep.eid -> WHERE ep.pid IS NULL -> and ep.eid is null -> and e.id=2 -> ORDER BY e.id; I reworte the statement like this and from doing so understand that, OK epeople as the pivot point between the two tables needs to be on the outside of the join - really placing it between the two tables. we're looking for people where there is no record match for epeople. SELECT lastname, firstname, title, event FROM events e LEFT JOIN epeople ep on e.id = ep.eid right join people p ON p.id = ep.pid WHERE ep.pid IS NULL and e.id=2 ORDER BY e.id; now whats the functional difference between this SELECT lastname, firstname, title, event FROM people p LEFT JOIN epeople ep on p.id = ep.pid right join events e on ep.eid = e.id WHERE ep.pid IS NULL and e.id = 2 ORDER BY ep.eid; and this SELECT lastname, firstname, title, event FROM people p LEFT JOIN epeople ep on p.id = ep.pid right join events e on ep.eid = e.id WHERE ep.pid IS NULL and ep.eid=2 ORDER BY e.id; as written the difference is in the and statements but in my result set ep.eid == e.id == 2 so why can't you use the second statement interchangably with the first? thanks for any insights, jb --------------------------------------------------------------------- Before posting, please check: http://www.mysql.com/manual.php (the manual) http://lists.mysql.com/ (the list archive) To request this thread, e-mail <[EMAIL PROTECTED]> To unsubscribe, e-mail <[EMAIL PROTECTED]> Trouble unsubscribing? Try: http://lists.mysql.com/php/unsubscribe.php --------------------------------------------------------------------- Before posting, please check: http://www.mysql.com/manual.php (the manual) http://lists.mysql.com/ (the list archive) To request this thread, e-mail <[EMAIL PROTECTED]> To unsubscribe, e-mail <[EMAIL PROTECTED]> Trouble unsubscribing? Try: http://lists.mysql.com/php/unsubscribe.php