SQL嵌套顺序由?

时间:2012-01-14 18:33:11

标签: mysql sql

我确信以前曾经问过这个问题,但我不知道该怎么称呼它才能找到答案。

我有一个类别和子类别表。它们每个都有一个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中是否可行,或者我是否需要使用多个查询

谢谢, 布拉德

4 个答案:

答案 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表达式处理该映射。