我确信以前曾经问过这个问题,但我不知道该怎么称呼它才能找到答案。
我有一个类别和子类别表。它们每个都有一个id和一个父id。如果它是顶级类别,则父ID为0.子类别的父ID设置为 它的父类别ID。
category_id # The ID for this record
category_name # The name of the category
parent_id # The parent ID for this category
display_order # Order of categories within their grouping
1 A 0 0 # First primary category
2 a1 1 0 # Subcategory, parent is A, display_order is 0
3 a2 1 1
4 a3 1 2
5 B 0 1 # Second primary category
6 b1 5 0 # Subcategory, parent is B, display_order is 0
7 b2 5 1
8 b3 5 2
我正在尝试编写一个SQL查询,它将按顺序为我提供所有类别:
A,a1,a2,a3,B,b1,b2,b3
SELECT * FROM categories ORDER BY display_order
这在SQL中是否可行,或者我是否需要使用多个查询
谢谢, 布拉德
答案 0 :(得分:8)
这样的事可能有用:
SELECT *
FROM categories
ORDER BY IF(parent_id, parent_id, category_id), parent_id, display_order
但由于它不能使用索引,因此速度很慢。 (虽然没有测试,可能是错的)
第一个ORDER BY
条件将父母和孩子排在一起;然后第二个确保父母先于其子女;第三个人将孩子们分开。
此外,它显然只适用于您直接描述的情况,即您有两级层次结构。
答案 1 :(得分:1)
答案已被接受,但我想我会分享我对此的想法。我也尝试在display_order列之后对主要类别进行排序。这是我的桌子
mysql> select * from categories;
+-------------+---------------+-----------+---------------+
| category_id | category_name | parent_id | display_order |
+-------------+---------------+-----------+---------------+
| 1 | B | 0 | 2 |
| 2 | C | 0 | 3 |
| 3 | b2 | 1 | 2 |
| 4 | b1 | 1 | 1 |
| 5 | c3 | 2 | 3 |
| 6 | A | 0 | 1 |
| 7 | c2 | 2 | 2 |
| 8 | b3 | 1 | 3 |
| 9 | a2 | 6 | 2 |
| 10 | a1 | 6 | 1 |
| 11 | c1 | 2 | 1 |
| 12 | a3 | 6 | 3 |
+-------------+---------------+-----------+---------------+
12 rows in set (0.00 sec)
如您所见,我非常谨慎地以非线性顺序添加类别:)
我的疑问:
SELECT
sub_id AS category_id,
sub_name AS category_name,
sub_parent_id AS parent_id,
main_order + sub_order AS display_order
FROM (
SELECT
c1.display_order + c1.display_order * (
SELECT
inner_c.display_order
FROM
categories AS inner_c
WHERE
inner_c.parent_id <> 0
ORDER BY
inner_c.display_order DESC
LIMIT 1) AS main_order,
c2.display_order AS sub_order,
c2.category_name AS sub_name,
c2.category_id AS sub_id,
c2.parent_id AS sub_parent_id
FROM
categories AS c1
JOIN
categories AS c2
ON
c1.category_id = c2.parent_id
WHERE
c1.parent_id = 0
) AS renumbered
UNION ALL
SELECT
category_id,
category_name,
parent_id,
display_order + display_order * (
SELECT
inner_c.display_order
FROM
categories AS inner_c
WHERE
inner_c.parent_id <> 0
ORDER BY
inner_c.display_order DESC
LIMIT 1) AS display_order
FROM
categories
WHERE
parent_id = 0
ORDER BY
display_order;
答案 2 :(得分:0)
听起来几乎与另一个我用类似的父/子层次结构回答,同时保留与其对应的父级相同的分组级别的子元素... Check this thread
答案 3 :(得分:0)
只要有可能,我会逐步构建SQL,尤其是因为它让我可以选择进行测试。
我们需要做的第一件事是确定顶级类别:
SELECT category_id AS tl_cat_id,
category_name AS tl_cat_name,
display_order AS tl_disp_order
FROM Categories
WHERE parent_id = 0;
现在我们需要将其与类别和子类别相结合以获得结果:
SELECT t.tl_cat_id, t.cat_name, t.tl_disp_order, c.category_id, c.category_name,
CASE WHEN c.parent_id = 0 THEN 0 ELSE c.display_order END AS disp_order
FROM Categories AS c
JOIN (SELECT category_id AS tl_cat_id,
category_name AS tl_cat_name,
display_order AS tl_disp_order
FROM Categories
WHERE parent_id = 0) AS t
ON c.tl_cat_id = t.parent_id OR (c.parent_id = 0 AND t.tl_cat_id = c.category_id)
ORDER BY tl_disp_order, disp_order;
连接条件不常见但应该有效;它收集父ID与当前类别ID相同的行,或父ID为0但类别ID相同的行。然后排序几乎是微不足道的 - 除了当您处理子类别排序时,您希望父项目位于列表的前面。 CASE表达式处理该映射。