如何在带日期的 GROUP_CONCAT 中使用 NOT IN 运算符 (<>)?
How to use the NOT IN operator (<>) in a GROUP_CONCAT with dates?
我有 日历 table,其中包含 2021 年 12 月的所有日期(我只会举例说明 table 中的一些日期,但是据了解,它实际上包含所述月份的所有日期):
ID
date
01
2021-12-01
02
2021-12-02
03
2021-12-03
04
2021-12-04
05
2021-12-05
我有 用户 table:
ID
name
num_employee
01
Andrew
101
02
Mary
102
我有table辅助
ID
date
num_employee
01
2021-12-03
101
02
2021-12-04
101
03
2021-12-03
102
04
2021-12-04
102
05
2021-12-05
101
06
2021-12-06
102
我进行了查询以显示员工编号、姓名、出勤天数和缺勤天数:
SELECT u.num_employee,
u.name,
a.date AS attendances,
c.date as faults FROM users u
JOIN (SELECT num_employee,
GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM date)) AS date FROM attendances
WHERE date BETWEEN '2021-12-01' AND '2021-12-31'
GROUP BY num_employee) a ON a.not_employee = u.num_employee
LEFT JOIN (SELECT GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM date)) AS date FROM calendar
WHERE date BETWEEN '2021-12-01' AND '2021-12-31') c ON c.date <> a.date
通过上面的查询,我得到了这个:
num_employee
name
assists
faults
101
Andrew
3,4,5
1,2,3,4,5,6,7,8,9,10...
102
Mary
3,4,6
1,2,3,4,5,6,7,8,9,10...
在考勤栏我获取的是12月份每个员工出勤的天数,而在faults我应该只获取缺勤的天数,但是12月份的所有天数显示。
我几乎可以肯定问题在于我如何评估 attends 列中显示的天数未显示在 absences栏目。具体这部分我认为我的评价是错误的:
ON c.date <> a.date
我的印象是,既然我在 GROUP_CONCAT
工作,我应该以不同的方式评估日期。我如何调整我的查询以获得以下内容?
not_employee
name
attendances
faults
101
Andrew
3,4,5
1,2,3,6,7,8,9,10...
102
Mary
3,4,6
1,2,5,7,8,9,10...
考虑到我正在使用的 MariaDB 版本,有问题的查询无法适应使用 CTE。我正在开发 phpMyAdmin。
一个解决方案是子选择。
这在 mysql 5 中也有效,在 mysql 8 中你可以从 attendense 中获得 CTE。
CREATE TABLE calendar (
`ID` INTEGER,
`date` VARCHAR(10)
);
INSERT INTO calendar
(`ID`, `date`)
VALUES
('01', '2021-12-01'),
('02', '2021-12-02'),
('03', '2021-12-03'),
('04', '2021-12-04'),
('05', '2021-12-05'),
('06', '2021-12-06'),
('07', '2021-12-07'),
('08', '2021-12-08'),
('09', '2021-12-09'),
('10', '2021-12-10'),
('11', '2021-12-11');
CREATE TABLE users (
`ID` INTEGER,
`name` VARCHAR(6),
`num_employee` INTEGER
);
INSERT INTO users
(`ID`, `name`, `num_employee`)
VALUES
('01', 'Andrew', '101'),
('02', 'Mary', '102');
CREATE TABLE attendances (
`ID` INTEGER,
`date` VARCHAR(10),
`num_employee` INTEGER
);
INSERT INTO attendances
(`ID`, `date`, `num_employee`)
VALUES
('01', '2021-12-03', '101'),
('02', '2021-12-04', '101'),
('03', '2021-12-03', '102'),
('04', '2021-12-04', '102'),
('05', '2021-12-05', '101'),
('06', '2021-12-06', '102');
SELECT u.num_employee,
u.name,
a.date AS attendances,
(SELECT GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM date)) AS date FROM calendar
WHERE date BETWEEN '2021-12-01' AND '2021-12-31'
AND NOT FIND_IN_SET(EXTRACT(DAY FROM date),a.date)) as faults FROM users u
JOIN (SELECT num_employee,
GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM date)) AS date FROM attendances
WHERE date BETWEEN '2021-12-01' AND '2021-12-31'
GROUP BY num_employee) a ON a.num_employee = u.num_employee
num_employee | name | attendances | faults
-----------: | :----- | :---------- | :----------------
101 | Andrew | 3,4,5 | 1,2,6,7,8,9,10,11
102 | Mary | 3,4,6 | 1,2,5,7,8,9,10,11
db<>fiddle here
考虑对所有可能的员工和日期成对匹配的用户和日历表进行交叉联接。然后 left join to assistance and 运行 aggregate GROUP_CONCAT
with one conditional expression for faults:
SELECT u.num_employee,
u.name,
GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM a.date)) AS attendances,
GROUP_CONCAT(DISTINCT
IF(a.date IS NULL, EXTRACT(DAY FROM c.date), NULL)
) AS faults
FROM calendar c
INNER JOIN users u
ON c.date BETWEEN '2021-12-01' AND '2021-12-31'
LEFT JOIN attendances a
ON c.date = a.date
AND u.num_employee = a.num_employee
AND a.date BETWEEN '2021-12-01' AND '2021-12-31'
GROUP BY u.num_employee,
u.name;
我有 日历 table,其中包含 2021 年 12 月的所有日期(我只会举例说明 table 中的一些日期,但是据了解,它实际上包含所述月份的所有日期):
ID | date |
---|---|
01 | 2021-12-01 |
02 | 2021-12-02 |
03 | 2021-12-03 |
04 | 2021-12-04 |
05 | 2021-12-05 |
我有 用户 table:
ID | name | num_employee |
---|---|---|
01 | Andrew | 101 |
02 | Mary | 102 |
我有table辅助
ID | date | num_employee |
---|---|---|
01 | 2021-12-03 | 101 |
02 | 2021-12-04 | 101 |
03 | 2021-12-03 | 102 |
04 | 2021-12-04 | 102 |
05 | 2021-12-05 | 101 |
06 | 2021-12-06 | 102 |
我进行了查询以显示员工编号、姓名、出勤天数和缺勤天数:
SELECT u.num_employee,
u.name,
a.date AS attendances,
c.date as faults FROM users u
JOIN (SELECT num_employee,
GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM date)) AS date FROM attendances
WHERE date BETWEEN '2021-12-01' AND '2021-12-31'
GROUP BY num_employee) a ON a.not_employee = u.num_employee
LEFT JOIN (SELECT GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM date)) AS date FROM calendar
WHERE date BETWEEN '2021-12-01' AND '2021-12-31') c ON c.date <> a.date
通过上面的查询,我得到了这个:
num_employee | name | assists | faults |
---|---|---|---|
101 | Andrew | 3,4,5 | 1,2,3,4,5,6,7,8,9,10... |
102 | Mary | 3,4,6 | 1,2,3,4,5,6,7,8,9,10... |
在考勤栏我获取的是12月份每个员工出勤的天数,而在faults我应该只获取缺勤的天数,但是12月份的所有天数显示。
我几乎可以肯定问题在于我如何评估 attends 列中显示的天数未显示在 absences栏目。具体这部分我认为我的评价是错误的:
ON c.date <> a.date
我的印象是,既然我在 GROUP_CONCAT
工作,我应该以不同的方式评估日期。我如何调整我的查询以获得以下内容?
not_employee | name | attendances | faults |
---|---|---|---|
101 | Andrew | 3,4,5 | 1,2,3,6,7,8,9,10... |
102 | Mary | 3,4,6 | 1,2,5,7,8,9,10... |
考虑到我正在使用的 MariaDB 版本,有问题的查询无法适应使用 CTE。我正在开发 phpMyAdmin。
一个解决方案是子选择。
这在 mysql 5 中也有效,在 mysql 8 中你可以从 attendense 中获得 CTE。
CREATE TABLE calendar ( `ID` INTEGER, `date` VARCHAR(10) ); INSERT INTO calendar (`ID`, `date`) VALUES ('01', '2021-12-01'), ('02', '2021-12-02'), ('03', '2021-12-03'), ('04', '2021-12-04'), ('05', '2021-12-05'), ('06', '2021-12-06'), ('07', '2021-12-07'), ('08', '2021-12-08'), ('09', '2021-12-09'), ('10', '2021-12-10'), ('11', '2021-12-11');
CREATE TABLE users ( `ID` INTEGER, `name` VARCHAR(6), `num_employee` INTEGER ); INSERT INTO users (`ID`, `name`, `num_employee`) VALUES ('01', 'Andrew', '101'), ('02', 'Mary', '102');
CREATE TABLE attendances ( `ID` INTEGER, `date` VARCHAR(10), `num_employee` INTEGER ); INSERT INTO attendances (`ID`, `date`, `num_employee`) VALUES ('01', '2021-12-03', '101'), ('02', '2021-12-04', '101'), ('03', '2021-12-03', '102'), ('04', '2021-12-04', '102'), ('05', '2021-12-05', '101'), ('06', '2021-12-06', '102');
SELECT u.num_employee, u.name, a.date AS attendances, (SELECT GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM date)) AS date FROM calendar WHERE date BETWEEN '2021-12-01' AND '2021-12-31' AND NOT FIND_IN_SET(EXTRACT(DAY FROM date),a.date)) as faults FROM users u JOIN (SELECT num_employee, GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM date)) AS date FROM attendances WHERE date BETWEEN '2021-12-01' AND '2021-12-31' GROUP BY num_employee) a ON a.num_employee = u.num_employee
num_employee | name | attendances | faults -----------: | :----- | :---------- | :---------------- 101 | Andrew | 3,4,5 | 1,2,6,7,8,9,10,11 102 | Mary | 3,4,6 | 1,2,5,7,8,9,10,11
db<>fiddle here
考虑对所有可能的员工和日期成对匹配的用户和日历表进行交叉联接。然后 left join to assistance and 运行 aggregate GROUP_CONCAT
with one conditional expression for faults:
SELECT u.num_employee,
u.name,
GROUP_CONCAT(DISTINCT EXTRACT(DAY FROM a.date)) AS attendances,
GROUP_CONCAT(DISTINCT
IF(a.date IS NULL, EXTRACT(DAY FROM c.date), NULL)
) AS faults
FROM calendar c
INNER JOIN users u
ON c.date BETWEEN '2021-12-01' AND '2021-12-31'
LEFT JOIN attendances a
ON c.date = a.date
AND u.num_employee = a.num_employee
AND a.date BETWEEN '2021-12-01' AND '2021-12-31'
GROUP BY u.num_employee,
u.name;