【问题标题】:MySQL Generate conditional result based on joinMySQL 根据 join 生成条件结果
【发布时间】:2019-09-03 23:28:34
【问题描述】:

我有 2 个表 - 部门和员工。

员工表:department_id 是来自部门表(id 列)的外键

|-------------|------------------|---------------|-----------------|
|      id     | employee_no      | department_id |employee_manager |
|-------------|------------------|---------------|-----------------|
|       1     |      34          |    1          |  Robert         |
|       2     |      34          |    1          |  Timothy        |
|       3     |      35          |    1          |  John           |
|       4     |      36          |    2          |  Benjamin       |
|       5     |      36          |    2          |  Bryan          |
|-------------|------------------|---------------|-----------------|

部门表:

|-------------|------------------|---------------|
|      id     |  department_name | dept_location |
|-------------|------------------|---------------|
|       1     |   Billing        |    CA         |
|       2     |  Marketing       |    NV         |
|-------------|------------------|---------------|

我需要一个 sql 查询的帮助,该查询返回employee 表中与department 表中的department_id 匹配且满足以下条件的所有行。

  1. 如果部门 id 匹配多个非唯一的employee_no(例如,department_id 1 匹配employee_no 34 和 35),则连接应从部门表中获取“CA”的 dept_location。

  2. 如果部门 id 匹配唯一的employee_no 甚至不止一次(例如,department_id 2 匹配employee_no 36 两次),则来自部门表的联接不适用,结果应为“NA”(不适用) 为 dept_location

我的结果应该如下表所示:

|-------------|------------------|---------------------|-----------------|
|      id     | employee_no      | department_location |employee_manager |
|-------------|------------------|---------------------|-----------------|
|       1     |      34          |   CA                |  Robert         |
|       2     |      34          |   CA                |  Timothy        |
|       3     |      35          |   CA                |  John           |
|       4     |      36          |   NA                |  Benjamin       |
|       5     |      36          |   NA                |  Bryan          |
|-------------|------------------|---------------------|-----------------|

【问题讨论】:

  • 如果department_id 与一个employee_no 完全匹配怎么办?
  • 如果department_id 只匹配一个employee_no,那么我们不应该加入dept_location 并且department_location 的结果应该是'NA'(不适用)。仅当有 2 个或更多非唯一的employee_no 时,与 dept_location 的连接才有效。我希望这是有道理的。谢谢!
  • 那么听起来条件 2 是无关紧要的,基本上如果该部门中有多个不同的员工,我们应该只输出部门位置?
  • @Nick 是的,你明白了。如果只有一名不同的员工,那么我们将部门位置硬编码为“NA”(在这种情况下不适用)而不进行任何联接。对不起,我不够精确。
  • @Nick 您的解决方案非常适合我。感谢您和其他人的时间和精力。

标签: mysql sql


【解决方案1】:

这是一个适用于 8.0 之前的 MySQL 版本的查询。它使用每个部门的不同员工计数的派生表来确定是显示部门位置还是NA

SELECT e.id, e.employee_no, 
       CASE WHEN c.distinct > 1 THEN d.dept_location
       ELSE 'NA'
       END AS department_location,
       e.employee_manager
FROM employees e
JOIN (SELECT department_id, COUNT(DISTINCT employee_no) AS `distinct`
      FROM employees
      GROUP BY department_id) c ON c.department_id = e.department_id
JOIN department d ON d.id = e.department_id

输出:

id  employee_no employee_manager    department_location
1   34          Robert              CA
2   34          Timothy             CA
3   35          John                CA
4   36          Benjamin            NA
5   36          Bryan               NA

Demo on dbfiddle

【讨论】:

    【解决方案2】:

    不太确定我是否理解,但在我看来,您可以使用派生字段,或者在最坏的情况下,使用 IF 在两个不同的派生公式之间进行选择:

    SELECT id, employee_no,       
        CASE (SELECT COUNT(*) FROM employees AS e WHERE e.department_id = employees.department_id)           
        WHEN 2 THEN 'CA' ELSE 'NA'      
    END AS department_location,     
    employee_manager FROM employees;
    

    测试

    CREATE TABLE department ( id integer, department_name varchar(30), dept_location varchar(30));
    INSERT INTO department VALUES (1, 'Billing', 'CA'), (2, 'Marketing', 'NV');
    
    CREATE TABLE employees (id integer, employee_no integer, department_id integer, employee_manager varchar(30));
    
    INSERT INTO employees VALUES
    (1, 34, 1, 'Robert'),
    (2, 34, 1, 'Timothy'),
    (3, 35, 1, 'John'),
    (4, 36, 2, 'Benjamin'),
    (5, 36, 2, 'Bryan');
    

    然后 SELECT 似乎正在工作:

    SELECT id, employee_no,       CASE (SELECT COUNT(*) FROM employees AS e WHERE e.department_id = employees.department_id)           WHEN 2 THEN 'NA' ELSE 'CA'      END AS department_location,     employee_manager FROM employees;
    +------+-------------+---------------------+------------------+
    | id   | employee_no | department_location | employee_manager |
    +------+-------------+---------------------+------------------+
    |    1 |          34 | CA                  | Robert           |
    |    2 |          34 | CA                  | Timothy          |
    |    3 |          35 | CA                  | John             |
    |    4 |          36 | NA                  | Benjamin         |
    |    5 |          36 | NA                  | Bryan            |
    +------+-------------+---------------------+------------------+
    5 rows in set (0.00 sec)
    

    【讨论】:

      【解决方案3】:

      这是一个依赖窗口函数的解决方案(在 MySQL 8.0 中可用),它避免了对子查询的需要。

      诀窍是比较每个部门的最小和最大员工人数。如果他们不同,那么我们肯定知道不止一名不同的员工属于给定的部门。

      SELECT
          e.id,
          e.employee_no,
          CASE 
              WHEN MAX(e.employee_no) OVER(PARTITION BY d.id) 
                  = MIN(e.employee_no) OVER(PARTITION BY d.id)
              THEN 'NA'
              ELSE 'CA'
          END department_location,
          e.employee_manager
      FROM employee e
      INNER JOIN department d ON e.department_id = d.id
      ORDER BY e.id
      

      demo on DB Fiddle 与您的示例数据返回:

      | id  | employee_no | employee_manager | department_location |
      | --- | ----------- | ---------------- | ------------------- |
      | 1   | 34          | Robert           | CA                  |
      | 2   | 34          | Timothy          | CA                  |
      | 3   | 35          | John             | CA                  |
      | 4   | 36          | Benjamin         | NA                  |
      | 5   | 36          | Bryan            | NA                  |
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-11
        • 1970-01-01
        • 2016-09-28
        • 1970-01-01
        相关资源
        最近更新 更多