MYSQL 8.0 带来所有结果,包括归零结果

MYSQL 8.0 Bring all results, including zeroed ones

业务规则:计算给定部门及其子部门的印刷量,即使没有印刷。

MySQL 8.0 版架构 SQL

CREATE TABLE IF NOT EXISTS `departments` (
  `id` INT NOT NULL,
  `name` VARCHAR(45) NOT NULL,
  `parent_department` INT NULL,
  PRIMARY KEY (`id`),
  INDEX `fk_department_department_idx` (`parent_department` ASC) VISIBLE,
  CONSTRAINT `fk_department_department`
    FOREIGN KEY (`parent_department`)
    REFERENCES `departments` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;

CREATE TABLE IF NOT EXISTS `prints` (
  `id` INT NOT NULL,
  `pages` INT NOT NULL,
  `copies` INT NOT NULL,
  `date` DATE NOT NULL,
  `department_id` INT NULL,
  `printer_id` INT NOT NULL,
  PRIMARY KEY (`id`),
  INDEX `fk_print_department1_idx` (`department_id` ASC) VISIBLE,
  CONSTRAINT `fk_print_department1`
    FOREIGN KEY (`department_id`)
    REFERENCES `departments` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;

insert into departments (id,name,parent_department)
values
(1,'Department 1',null),
(2,'Department 2',null),
(3,'Department 3',1),
(4,'Department 4',null),
(5,'Department 5',1);

insert into prints (id,pages,copies,date,department_id,printer_id)
values
(1,3,1,'2019-06-30',2,1),
(2,8,2,'2019-06-30',3,2),
(3,10,2,'2020-12-02',2,6),
(4,3,1,'2020-12-02',1,4),
(5,9,2,'2020-12-02',1,1),
(6,5,3,'2020-12-05',2,5),
(7,5,7,'2020-12-05',1,4),
(8,3,2,'2020-12-05',1,1),
(9,1,1,'2020-12-25',2,3),
(10,4,1,'2020-12-25',1,2),
(11,9,2,'2020-12-25',1,1);

查询:

SET @initial_date = '2020-12-01';
SET @final_date = '2020-12-15';
SET @department_id = 1;

WITH RECURSIVE CTE AS
(
  SELECT
    d1.id, d1.name, d1.parent_department
  FROM
    departments d1
  WHERE d1.id=@department_id
  
  UNION ALL

  SELECT
    d3.id, d3.name, d3.parent_department
  FROM
  CTE dCTE, departments d3
  WHERE d3.parent_department = dCTE.id
)

SELECT
  dCTE.id,
  dCTE.name AS department,
  d4.name AS parent_department,
  COALESCE(SUM(i.copies * i.pages), 0) AS total_print,
COUNT(DISTINCT i.printer_id) AS printer_count
FROM CTE dCTE
LEFT JOIN departments d4 ON d4.id = dCTE.parent_department
LEFT JOIN prints i ON i.department_id = dCTE.id
WHERE (i.date IS NULL OR i.date BETWEEN @initial_date AND @final_date)
GROUP BY dCTE.id, dCTE.name, d4.name
ORDER BY total_print DESC, department ASC

实际结果:

id  department     parent_department   total_print  printer_count
1   Department 1          null              62            2
5   Department 5       Department 1         0             0

预期结果:

id  department     parent_department   total_print  printer_count
1   Department 1          null              62            2
3   Department 3       Department 1         0             0   <--- this is the missing row
5   Department 5       Department 1         0             0

Fiddle: https://www.db-fiddle.com/f/7FLxFS2nfyUPJdXWPRjSpF/3

问题:由于某种原因,其中一个子部门没有返回。

有什么想法吗?

感谢帮助

最终它被 WHERE 子句过滤掉了。 JOIN 检测部门 3 记录:

name id pages copies date department_id printer_id
Department 3 2 8 2 2019-06-30 3 2

但是随后 WHERE 子句根据过滤器检查该记录的打印日期:

...
WHERE (i.date IS NULL OR i.date BETWEEN @initial_date AND @final_date)

由于 date 值不为空,因此将其与日期范围(2020-12-012020-12-15)进行比较。由于 2019-06-30 明显超出该范围,因此删除该记录。

相反,将日期过滤器移动到 LEFT JOIN 语句中:

...
SELECT
      dCTE.id,
      dCTE.name AS department,
      d4.name AS parent_department,
      COALESCE(SUM(i.copies * i.pages), 0) AS total_print,
      COUNT(DISTINCT i.printer_id) AS printer_count
FROM CTE dCTE
LEFT JOIN departments d4 ON d4.id = dCTE.parent_department
LEFT JOIN prints i ON i.department_id = dCTE.id
      AND i.date BETWEEN @initial_date AND @final_date
GROUP BY dCTE.id, dCTE.name, d4.name
ORDER BY total_print DESC, department ASC