SQL 算法分类器

SQL Algorithm Sorter

这是我的 table 数据。如果 cat_parent_id 为 0,则表示它是 parent,例如,人与文化是 parent,cat_id = 1,员工福利和认证是 child人与文化。但是,员工福利和认证也有 child。 Employee Benefits cat_id = 6,所以他的 child 是 SSS Loan Inquiry,而 Certification 有 cat_id = 10,Certificate of Employment 和 SSS Certificate Of Contributions 将是他的 child .

预期输出:

Admin and Facilities
  • Safety and Security Related Concerns
     • CCTV Footage

Information Technology
  • User Account
     • Enable / Disable Access

People and Culture
     • Certification
        • Certificate of Employment
        • SSS Certificate of Employment
     • Employee Benefits Request
        • SSS Loan Inquiry

我现在有这样的东西,运气不好。

SELECT category.cat_id AS catId, category.cat_parent_id AS catParentId, 
subcategory.cat_id AS subcatId,subcategory.cat_parent_id AS subcatParentId,
category.cat_name,
CONCAT( IFNULL(subcategory.cat_parent_id, category.cat_parent_id), 
category.cat_parent_id, category.cat_id, category.cat_name) AS sorter
FROM ticket_categories AS category
LEFT JOIN ticket_categories AS subcategory ON subcategory.cat_parent_id = 
category.cat_id
GROUP BY category.cat_id
ORDER BY sorter

主要目标是按 parent(第一优先级)、类别(第二优先级)、子类别(第三优先级)的字母顺序对数据进行排序。我正在玩我的别名分类器,但我无法让它工作。

在MySQL8之前的版本中,递归查询比较棘手。在您的情况下,您似乎只有 3 个级别(0、1 和 2),因此最好只 self-outer-join 您的 table 多次以获得从根到每个节点的路径。

最后对 "path" 中从根到子的名称串联进行排序:

select a.cat_id, a.cat_level, a.cat_name, 
    concat(
        ifnull(concat(c.cat_name, '  '), ''),
        ifnull(concat(b.cat_name, '  '), ''),
        a.cat_name) as cat_order
from ticket_categories a
left join ticket_categories b on b.cat_id = a.cat_parent_id 
left join ticket_categories c on c.cat_id = b.cat_parent_id 
order by cat_order;

您可以轻松扩展此查询以支持更多级别;只需添加那么多 left join 行和 table 别名并相应地扩展 concat 表达式。

在 MySQL 8 中,您可以使用可以处理任意数量级别的递归查询:

with recursive cte(cat_id, cat_level, cat_name, cat_order) as (
  select cat_id, cat_level, cat_name, cat_name
  from ticket_categories
  where cat_parent_id = 0
  union
  select t.cat_id, t.cat_level, t.cat_name, concat(cte.cat_order, '  ', t.cat_name)  
  from cte
  inner join ticket_categories t on t.cat_parent_id = cte.cat_id
)
select * from cte
order by cat_order;

两个查询的输出:

cat_id | cat_level | cat_name                             | cat_order
-------+-----------+--------------------------------------+-------------------------------------------------------------------------------
   3   |     0     | Admin and Facilities                 | Admin and Facilities
   4   |     1     | Safety and Security Related Concerns | Admin and Facilities  Safety and Security Related Concerns
   9   |     2     | CCTV Footage Request                 | Admin and Facilities  Safety and Security Related Concerns  CCTV Footage Request
   2   |     0     | Information Technology               | Information Technology
   5   |     1     | User Account                         | Information Technology  User Account
   8   |     2     | Enable / Disable Access              | Information Technology  User Account  Enable / Disable Access
   1   |     0     | People and Culture                   | People and Culture
  10   |     1     | Certification                        | People and Culture  Certification
  11   |     2     | Certificate of Employment            | People and Culture  Certification  Certificate of Employment
  12   |     2     | SSS Certificate of Contributions     | People and Culture  Certification  SSS Certificate of Contributions

双精度 space 用作路径中的分隔符 (cat_order)。这假设您的名字中不会有双 space。如果你愿意,如果还有你的名字中一个是另一个的前缀,那么顺序可能会出错。

对于最终的缩进格式,您将使用 cat_level 列。但是在我看来这样的任务不属于SQL,虽然用

很容易做到
concat(repeat('  ', cat_level), cat_name)

A db fiddle 两个查询。