查询以查找已经超过x次的成对的员工及其部门

时间:2019-09-20 15:40:41

标签: mysql sql

我的模式:

CREATE TABLE employees
    (`emp_no` int not null primary key)
;

INSERT INTO employees
    (`emp_no`)
VALUES
    (10001),
    (10002),
    (10003),
    (10004),
    (10005),
    (10006),
    (10007),
    (10008),
    (10009),
    (10010)
;


CREATE TABLE departments
    (`dept_no` varchar(4) not null primary key)
;

INSERT INTO departments
    (`dept_no`)
VALUES
    ('d009'),
    ('d005'),
    ('d002'),
    ('d003'),
    ('d001'),
    ('d004'),
    ('d006'),
    ('d008'),
    ('d007'),
    ('d010')
;

CREATE TABLE `dept_emp` (
  `emp_no` int(11) NOT NULL,
  `dept_no` char(4) NOT NULL,
  `from_date` date NOT NULL,
  `to_date` date NOT NULL,
  PRIMARY KEY (`emp_no`,`dept_no`),
  KEY `dept_no` (`dept_no`),
  CONSTRAINT `dept_emp_ibfk_1` FOREIGN KEY (`emp_no`) REFERENCES `employees` (`emp_no`) ON DELETE CASCADE,
  CONSTRAINT `dept_emp_ibfk_2` FOREIGN KEY (`dept_no`) REFERENCES `departments` (`dept_no`) ON DELETE CASCADE
); 

INSERT INTO dept_emp
    (`emp_no`, `dept_no`, `from_date`, `to_date`)
VALUES
    (10001, 'd005', '1986-06-26 00:00:00', '2000-01-01 00:00:00'),
    (10001, 'd006', '2000-01-01 00:00:00', '2002-01-01 00:00:00'),
    (10001, 'd009', '2002-01-01 00:00:00', '2003-01-01 00:00:00'),
    (10001, 'd001', '2003-01-01 00:00:00', '2009-01-01 00:00:00'),
    (10002, 'd007', '1996-08-03 00:00:00', '2001-01-01 00:00:00'),
    (10002, 'd006', '2001-01-01 00:00:00', '2002-01-01 00:00:00'),
    (10002, 'd009', '2002-01-01 00:00:00', '2003-01-01 00:00:00'),
    (10002, 'd008', '2003-01-01 00:00:00', '2003-06-01 00:00:00'),
    (10002, 'd001', '2003-06-01 00:00:00', '2004-09-01 00:00:00'),
    (10002, 'd002', '2004-06-01 00:00:00', '2005-09-01 00:00:00'),
    (10002, 'd003', '2005-09-01 00:00:00', '2006-09-01 00:00:00'),
    (10002, 'd010', '2006-09-01 00:00:00', '2010-09-01 00:00:00'),
    (10003, 'd004', '1995-12-03 00:00:00', '1996-12-03 00:00:00'),
    (10003, 'd005', '1996-12-03 00:00:00', '1997-12-03 00:00:00'),
    (10003, 'd001', '1997-12-03 00:00:00', '2002-06-03 00:00:00'),
    (10004, 'd004', '1986-12-01 00:00:00', '2000-01-01 00:00:00'),
    (10004, 'd008', '2000-01-01 00:00:00', '2003-01-01 00:00:00'),
    (10004, 'd005', '2003-01-01 00:00:00', '2005-01-01 00:00:00'),
    (10005, 'd003', '1989-09-12 00:00:00', '2000-01-01 00:00:00'),
    (10005, 'd002', '2000-01-01 00:00:00', '2003-06-01 00:00:00'),
    (10005, 'd006', '2003-06-01 00:00:00', '2009-06-01 00:00:00'),
    (10006, 'd005', '1990-08-05 00:00:00', '9999-01-01 00:00:00'),
    (10007, 'd008', '1989-02-10 00:00:00', '2000-01-01 00:00:00'),
    (10007, 'd007', '2000-01-01 00:00:00', '2003-01-01 00:00:00'),
    (10007, 'd009', '2003-01-01 00:00:00', '2009-01-01 00:00:00'),
    (10008, 'd005', '1998-03-11 00:00:00', '2000-07-31 00:00:00'),
    (10008, 'd001', '2000-07-31 00:00:00', '2004-07-31 00:00:00'),
    (10009, 'd006', '1985-02-18 00:00:00', '2002-01-01 00:00:00'),
    (10009, 'd007', '2002-02-18 00:00:00', '2003-01-01 00:00:00'),
    (10009, 'd008', '2003-02-18 00:00:00', '2004-01-01 00:00:00'),
    (10009, 'd005', '2004-02-18 00:00:00', '2005-01-01 00:00:00'),
    (10009, 'd003', '2005-02-18 00:00:00', '2006-01-01 00:00:00'),
    (10009, 'd002', '2006-02-18 00:00:00', '2007-01-01 00:00:00'),
    (10009, 'd010', '2007-02-18 00:00:00', '2009-01-01 00:00:00')
;

我尝试了以下查询:

SELECT 
    e1.emp_no,
    de1.dept_no,
    e2.emp_no,
    COUNT(DISTINCT de1.dept_no) Total
FROM
    employees e1
        JOIN
    employees e2 ON e1.emp_no < e2.emp_no
        JOIN
    dept_emp de1 ON de1.emp_no = e1.emp_no
        JOIN
    dept_emp de2 ON de2.emp_no = e2.emp_no
        AND de2.dept_no = de1.dept_no
        AND de1.from_date <= de2.to_date
        AND de2.from_date <= de1.to_date
GROUP BY e2.emp_no, e1.emp_no
HAVING Total > x;

输出

| emp_no | dept_no | emp_no | Total |
|--------|---------|--------|-------|
|  10001 |    d006 |  10002 |     3 |
|  10002 |    d009 |  10007 |     2 |
|  10001 |    d005 |  10008 |     2 |
|  10002 |    d010 |  10009 |     4 |



该查询只是给我一个 dept_no
我想要它们一起出现的所有 dept_no 的列表,如下面的示例:

| emp_no | dept_no | emp_no | Total |
|--------|---------|--------|-------|
|  10001 |    d006 |  10002 |     3 |
|  10001 |    d001 |  10002 |     3 |
|  10001 |    d009 |  10002 |     3 |
|  10002 |    d009 |  10007 |     2 |
|  10002 |    d007 |  10007 |     2 |
|  10001 |    d005 |  10008 |     2 |
|  10001 |    d001 |  10008 |     2 |
|  10002 |    d010 |  10009 |     4 |
|  10002 |    d008 |  10009 |     4 |
|  10002 |    d003 |  10009 |     4 |
|  10002 |    d006 |  10009 |     4 |


SQL Fiddle

2 个答案:

答案 0 :(得分:0)

您的查询看起来不错,但是聚合使事情变得混乱。在MySQL 8.0中,您可以摆脱聚合并在内部查询中进行窗口计数。然后外部查询根据计数进行过滤。

SELECT *
FROM (
    SELECT 
        e1.emp_no emp_no1,
        de1.dept_no,
        e2.emp_no emp_no2,
        COUNT(*) OVER(PARTITION BY e1.emp_no, e2.emp_no) cnt
    FROM
        employees e1
            JOIN
        employees e2 ON e1.emp_no < e2.emp_no
            JOIN
        dept_emp de1 ON de1.emp_no = e1.emp_no
            JOIN
        dept_emp de2 ON de2.emp_no = e2.emp_no
            AND de2.dept_no = de1.dept_no
            AND de1.from_date <= de2.to_date
            AND de2.from_date <= de1.to_date
) x 
WHERE cnt > 1
ORDER BY emp_no1, emp_no2, dept_no 

Demo on DB Fiddle

| emp_no1 | dept_no | emp_no2 | cnt |
| ------- | ------- | ------- | --- |
| 10001   | d001    | 10002   | 3   |
| 10001   | d006    | 10002   | 3   |
| 10001   | d009    | 10002   | 3   |
| 10001   | d001    | 10008   | 2   |
| 10001   | d005    | 10008   | 2   |
| 10002   | d007    | 10007   | 2   |
| 10002   | d009    | 10007   | 2   |
| 10002   | d003    | 10009   | 4   |
| 10002   | d006    | 10009   | 4   |
| 10002   | d008    | 10009   | 4   |
| 10002   | d010    | 10009   | 4   |

答案 1 :(得分:0)

您可以使用GROUP_CONCAT()以逗号分隔的列表形式返回所有部门:

SELECT 
    e1.emp_no,
    GROUP_CONCAT(de1.dept_no) as dept_nos,
    e2.emp_no,
    COUNT(DISTINCT de1.dept_no) Total
FROM
    employees e1
        JOIN
    employees e2 ON e1.emp_no < e2.emp_no
        JOIN
    dept_emp de1 ON de1.emp_no = e1.emp_no
        JOIN
    dept_emp de2 ON de2.emp_no = e2.emp_no
        AND de2.dept_no = de1.dept_no
        AND de1.from_date <= de2.to_date
        AND de2.from_date <= de1.to_date
GROUP BY e2.emp_no, e1.emp_no
HAVING Total > 1;

结果:

| emp_no | dept_nos            | Total | emp_no |
| ------ | ------------------- | ----- | ------ |
| 10001  | d006,d009,d001      | 3     | 10002  |
| 10002  | d009,d007           | 2     | 10007  |
| 10001  | d005,d001           | 2     | 10008  |
| 10002  | d008,d010,d003,d006 | 4     | 10009  |

View on DB Fiddle

这看起来与您的预期结果有所不同,但是它以更紧凑的形式包含了相同的信息。

请注意,您的原始查询是不确定的,并且在启用ONLY_FULL_GROUP_BY模式时会导致错误,这是自MySQL 5.7起的默认设置。

如果您不需要employees表中的任何数据,也不需要查询它们。

SELECT 
    de1.emp_no,
    GROUP_CONCAT(de1.dept_no) as dept_nos,
    de2.emp_no,
    COUNT(DISTINCT de1.dept_no) Total
FROM
    dept_emp de1
        JOIN
    dept_emp de2
        ON  de2.dept_no = de1.dept_no
        AND de2.emp_no  > de1.emp_no
        AND de1.from_date <= de2.to_date
        AND de2.from_date <= de1.to_date
GROUP BY de2.emp_no, de1.emp_no
HAVING Total > 1;

这将返回相同的结果。

View on DB Fiddle