Select users belonging only to particular departments

后端 未结 12 2288
挽巷
挽巷 2021-02-18 12:49

I have the following table with two fields namely a and b as shown below:

create table employe
(
    empID varchar(10),
    department varchar(10)
);
         


        
12条回答
  •  梦如初夏
    2021-02-18 13:52

    You can too use GROUP BY and HAVING — you just need to do it in a subquery.

    For example, let's start with a simple query to find all employees in departments X and Y (and not in any other departments):

    SELECT empID,
      GROUP_CONCAT(DISTINCT department ORDER BY department ASC) AS depts
    FROM emp_dept GROUP BY empID
    HAVING depts = 'X,Y'
    

    I've used MySQL's GROUP_CONCAT() function as a convenient shortcut here, but you could get the same results without it, too, e.g. like this:

    SELECT empID,
      COUNT(DISTINCT department) AS all_depts,
      COUNT(DISTINCT CASE
        WHEN department IN ('X', 'Y') THEN department ELSE NULL
      END) AS wanted_depts
    FROM emp_dept GROUP BY empID
    HAVING all_depts = wanted_depts AND wanted_depts = 2
    

    Now, to combine this with other query condition, simply take a query that includes the other conditions, and join your employees table against the output of the query above:

    SELECT empID, name, depts
    FROM employees
    JOIN (
        SELECT empID,
          GROUP_CONCAT(DISTINCT department ORDER BY department ASC) AS depts
        FROM emp_dept GROUP BY empID
        HAVING depts = 'X,Y'
      ) AS tmp USING (empID)
    WHERE -- ...add other conditions here...
    

    Here's an SQLFiddle demonstrating this query.


    Ps. The reason why you should use a JOIN instead of an IN subquery for this is because MySQL is not so good at optimizing IN subqueries.

    Specifically (as of v5.7, at least), MySQL always converts IN subqueries into dependent subqueries, so that the subquery must be re-executed for every row of the outer query, even if the original subquery was independent. For example, the following query (from the documentation linked above):

    SELECT ... FROM t1 WHERE t1.a IN (SELECT b FROM t2);
    

    gets effectively converted into:

    SELECT ... FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.b = t1.a);
    

    This may still be reasonably fast, if t2 is small and/or has an index allowing fast lookups. However, if (like in the original example above) executing the subquery might take a lot of work, the performance can suffer badly. Using a JOIN instead allows the subquery to only be executed once, and thus typically offers much better performance.

提交回复
热议问题