简体   繁体   中英

How to select records with no matches in the foreign table (Left outer join)

I have one table that holds my ressources:

Ressource | Ressource-ID

And a table that holds the associations

Ressource-ID | Employee-ID

How to select the ressources of an Employee that are available, ie not in the association table?

I've tried this, but it's not working:

select r.ress, r.ress_id
FROM Ressource r
LEFT outer JOIN Ressource_Employee_Association a ON r.ress_id = a.ress_id
WHERE a.emp_id = 'ID00163efea66b' and a.ress_id IS NULL

Any ideas?

Thanks Thomas

The WHERE clause is applied after the LEFT JOIN. This means that you are currently trying to get results where there is NO matching record in Ressource_Employee_Association, but where the emp_id equals 'ID00163efea66b' .

But if there is no matching record, how can emp_id be anything other than NULL ?

One option is to move part of the WHERE clause into the join...

SELECT
  r.ress, r.ress_id
FROM
  Ressource r
LEFT OUTER JOIN
  Ressource_Employee_Association a
    ON r.ress_id = a.ress_id
    AND a.emp_id = 'ID00163efea66b'
WHERE
  a.ress_id IS NULL

This will list all resources that are not associated to employee 'ID00163efea66b' .

EDIT

Your comment implies that what you want is...
- A view listing all employees
- For each employee list each resource that they DON'T have

This requires an extra table listing all of your employees.

SELECT
  *
FROM
  Employee
CROSS JOIN
  Ressource
WHERE
  NOT EXISTS (SELECT * FROM Ressource_Employee_Association
               WHERE emp_id  = Employee.id
                 AND ress_id = Ressource.id)

Does this work?

select r.ress, r.ress_id
from resource r
where not exists 
(
    select 1 from ressource_emplyee_association a 
    where a.emp_id = '...' and a.ress_id = r.ress_id
)

EDIT
Before that I had the following, but changed it according to the comments below:

select r.ress, r.ress_id
from resource r
where not exists 
(
    select top 1 1 from ressource_emplyee_association a 
    where a.emp_id = '...' and a.ress_id = r.ress_id
)
SELECT * 
  FROM Ressource
 WHERE ress_id IN (
                   SELECT ress_id, 
                     FROM Ressource 
                   MINUS
                   SELECT ress_id
                     FROM Ressource_Employee_Association 
                    WHERE emp_id = 'ID00163efea66b'
                  );

After writing my above comments, and looking at the proposed solutions: I think I've got some more understanding of what you are trying to do.

Assuming you have unlimited quantity of resources in your resources table, you want to select the un-assigned resources per employee (based on their non-existence for any specific employee in the resource association table).

In order to accomplish this (and get a comprehensive list of employees) you'll need a 3rd table, in order to reference the complete list of employees. You'll also need to CROSS JOIN all of the resources onto the list of employees (assuming every employee has access to every resource), then you LEFT JOIN ( LEFT OUTER JOIN whatever) your association list onto the query where the resource_id and employee_id match the resource_id in the resources table, and the employee_id in the employees table (respectively). THEN you add your where clause that filters out all the records that assign an employee to a resource. This leaves you with the resources that are available to the employee, which they also do not have signed out. This is convoluted to say, so hopefully the query sheds more light:

SELECT e.employee_id, e.employee, r.res_id, r.res

FROM employees e
CROSS JOIN resources r
LEFT JOIN assigned_resources ar
    ON ar.employee_id = e.employee_id AND r.res_id = ar.res_id

WHERE ar.res_id IS NULL

If you don't have an employees table, you can accomplish the same by using the assigned resources table, but you will be limited to selecting employees who already have some resources allocated. You'll need to add a GROUP BY query because of the possible existence of multiple employee definitions in the association table. Here's what that query would look like:

SELECT e.employee_id, r.res_id, r.res

FROM assigned_resources e
CROSS JOIN resources r
LEFT JOIN assigned_resources ar
    ON ar.employee_id = e.employee_id AND r.res_id = ar.res_id

WHERE ar.res_id IS NULL

GROUP BY e.employee_id, r.res_id

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM