Запрос, чтобы найти пары сотрудников и их отдел, которые были сотрудниками более х раз - PullRequest
1 голос
/ 20 сентября 2019

Моя схема:

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 голосов
/ 20 сентября 2019

Вы можете использовать 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  |

Показать на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;

Это вернет тот же результат.

Просмотр на БД Fiddle

0 голосов
/ 20 сентября 2019

Ваш запрос выглядит не плохо, но агрегация - это то, где что-то запутывается.В 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 

Демонстрация на 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   |
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...