简体   繁体   中英

COUNT or UNION or both?

I'm trying to get a resultset with the following parameters from my DB in one query:

  • Employees that are not active in project ? AND
  • Employees that are not active in 3 projects

The first part is easy but the second part is tricky. And I need to combine the both into one query.

Here are my simplified tables:


employeeid | ...


projectid | active | ...

"active" can be A (for active) or R (for refused).

SELECT name
FROM employee e
INNER JOIN project_employee pe
ON e.employeeid = pe.employeeid
WHERE projectid != ?

EDIT: != instad of =

-> That gives me all the employees that are not in project ? But how can I make the second part work? I figured it had to be something with SELECT COUNT(DISTINCT... but all my tries have been failures.

If I get the question right, you'll want something that resembles this in the end:

 select employees.employee_id
   from employees
left join projects
       on projects.employee_id = employees.employee_id
      and projects.active = 'A'
group by employees.employee_id
having count(*) < 3
   and bool_and(projects.project_id <> ?)
  • Left join: include employees with no projects at all
  • Having count: less than 3 projects
  • Having bool_and: exclude employees in a specific project

If your query does indeed get all employees that are not active in project ? than you could do something like this for the employees not active in three or more projects:

SELECT name
FROM employee e INNER JOIN project_employee pe ON e.employeeid = pe.employeeid
GROUP BY e.employeeid
HAVING COUNT(*) >= 3

Actually, your query gives you employees who are in a project. To get those who are not, you need something like this:

select name
from employee e join
(select employee_id
from employee
except
select employee_id
project_employee 
where projected = ?) temp on temp.employee_id = employee.employee_id

To get employees who are not active in 3 projects with status A, do something similar. To get the final answer, union the two queries together.

Another solution is to use NOT IN

SELECT name
FROM employee e
INNER JOIN project_employee pe
ON e.employeeid = pe.employeeid
WHERE projectid NOT IN (1, 5, 9)-- ids of the 3 projects, you've talked about

This gives names of employees that are not active ie active='R' in 3 projects

SELECT name
FROM employee e
INNER JOIN project_employee pe
ON e.employeeid = pe.employeeid
WHERE active='R'
GROUP BY name
HAVING COUNT(projectid)=3

But when you are going to do UNION of above resultset with resultset obtained from first condition ie employess not active in project

SELECT name
FROM employee e
INNER JOIN project_employee pe
ON e.employeeid = pe.employeeid
WHERE active='R'

then the first query posted above ie employees inactive in 3 projects is pointless because employees not active in exactly 3 projects are also employees not active in a particular project and thus you would get same final resultset everytime.

eg

Employees inactive

xyz
pqr
mno
lmn
abc

Employees inactive in 3 projects

xyz
lmn

Applying union

xyz
pqr
mno
lmn
abc

UNION

xyz
lmn

Final Resultset which is same as 1st resultset

xyz
pqr
mno
lmn
abc

I would start from a query that gives employees active in 3 projects.
This query gives employess that are active in 3 or more projects:

SELECT DISTINCT pe1.employeeid
FROM project_employee pe1
JOIN project_employee pe2 
  ON pe1.employeeid = pe2.employeeid
  AND pe1.projectid < pe2.projectid
JOIN project_employee pe3
  ON pe2.employeeid = pe3.employeeid
  AND pe2.projectid < pe3.projectid
WHERE  pe1.active = 'A'
  AND  pe2.active = 'A'
  AND  pe3.active = 'A'

If we want employess acive in exactly 3 projects, then this condition in the where clause can help:

   AND NOT EXISTS(
      SELECT 1 FROM project_employee pe4
      WHERE pe3.employeeid = pe4.employeeid
        AND pe3.projectid < pe4.projectid
        AND pe4.active = 'A'
   )

And now - simply - add the below condition to the original query:

 ........
 AND employe_id NOT IN (
    SELECT pe1.employeeid
    .......  
    put the above query here
    .......
    .......
 )

The final query may look like:

SELECT name
FROM employee e
INNER JOIN project_employee pe
ON e.employeeid = pe.employeeid
WHERE projectid != ?
  AND e.employeeid NOT IN (
      SELECT pe1.employeeid
      FROM project_employee pe1
      JOIN project_employee pe2 
        ON pe1.employeeid = pe2.employeeid
        AND pe1.projectid < pe2.projectid
      JOIN project_employee pe3
        ON pe2.employeeid = pe3.employeeid
        AND pe2.projectid < pe3.projectid
      WHERE  pe1.active = 'A'
        AND  pe2.active = 'A'
        AND  pe3.active = 'A'
      /* --- uncomment when exactly 3 projects are required
       AND NOT EXISTS(
           SELECT 1 FROM project_employee pe4
           WHERE pe3.employeeid = pe4.employeeid
             AND pe3.projectid < pe4.projectid
             AND pe4.active = 'A'
       )    
      */ 
)

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