SQL - 如何聚合和排序父子树?

时间:2017-08-04 08:47:50

标签: mysql sql recursive-query

我有以下表格。工作可以分为多个类别。类别具有父类别。类别只有两个层次。工作仅归入第二级别类别。我想要一个所有类别的列表,其中包含针对每个类别分类的作业计数以及父类别的总计。

以下是表格:

CREATE TABLE jobs (
    id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
    title varchar(255) NOT NULL,
    description text NOT NULL
) ENGINE=InnoDB;


CREATE TABLE categories (
   id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
   name varchar(255) NOT NULL,
   parent_id INT NOT NULL
) ENGINE=InnoDB;


CREATE TABLE job_categories (
    job_id INT UNSIGNED NOT NULL,
    category_id INT UNSIGNED NOT NULL,
    PRIMARY KEY (`job_id`, `category_id`),
    FOREIGN KEY fk_job_id(job_id) REFERENCES jobs(id),
    FOREIGN KEY fk_category_id(category_id) REFERENCES categories(id)
) ENGINE=InnoDB;


INSERT INTO categories (id, name, parent_id) VALUES(1, 'Science', 0),(2, 'Biology', 1), (3, 'Chemistry', 1);
INSERT INTO job_categories (job_id, category_id) VALUES(1,2),(1,3), (2,2), (3,2), (4,3);

这是我的SQL尝试:

SELECT one.name AS name
     , one.name AS sortkey1
     , CAST(NULL AS UNSIGNED) AS sortkey2
     , COUNT(three.job_id) AS total 
  FROM categories AS one
  INNER JOIN categories AS two ON two.parent_id = one.id
  LEFT JOIN job_categories AS three ON three.category_id = two.id
  WHERE one.parent_id = 0
  GROUP BY name, sortkey1, sortkey2
UNION ALL
SELECT CONCAT('  ',two.name) AS name
     , one.name AS sortkey1
     , two.name AS sortkey2
     , COUNT(three.job_id) AS total 
  FROM categories AS one
  INNER JOIN categories AS two ON two.parent_id = one.id
  LEFT JOIN job_categories AS three ON three.category_id = two.id
  WHERE one.parent_id = 0
  GROUP BY name, sortkey1, sortkey2
ORDER BY sortkey1 , sortkey2

这就是我想要实现的目标,例如,如果发布了4个工作,其中3个工作被归类为生物学,4个中的2个被分类为化学 - 上面的sql没有为父母提供正确的总数范畴科学。我得到5而不是4:

name            sortkey1      sortkey2     total
Science         Science                     4 
   Biology      Science       Biology       3
   Chemistry    Science       Chemistry     2

任何帮助表示感谢。

1 个答案:

答案 0 :(得分:1)

SELECT one.name AS name
 , one.name AS sortkey1
 , CAST(NULL AS UNSIGNED) AS sortkey2
 , COUNT(DISTINCT three.job_id) AS total 
FROM categories AS one
INNER JOIN categories AS two ON two.parent_id = one.id
LEFT JOIN job_categories AS three ON three.category_id = two.id
WHERE one.parent_id = 0
GROUP BY name, sortkey1, sortkey2
UNION ALL
SELECT CONCAT('  ',two.name) AS name
 , one.name AS sortkey1
 , two.name AS sortkey2
 , COUNT(three.job_id) AS total 
FROM categories AS one
INNER JOIN categories AS two ON two.parent_id = one.id
LEFT JOIN job_categories AS three ON three.category_id = two.id
WHERE one.parent_id = 0
GROUP BY name, sortkey1, sortkey2
ORDER BY sortkey1 , sortkey2