【问题标题】:SQL nested order by?SQL 嵌套排序依据?
【发布时间】:2012-01-14 18:33:10
【问题描述】:

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

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

谢谢, 布拉德

【问题讨论】:

  • 你能举个输入数据的例子吗?不仅输出...
  • 子类可以依次有子类吗?
  • 添加了表格数据的示例
  • 保留主要类别的display_order重要吗?

标签: mysql sql


【解决方案1】:

这样的事情可能会起作用:

SELECT *
FROM categories
ORDER BY IF(parent_id, parent_id, category_id), parent_id, display_order

但由于它不能使用索引,所以它会很慢。 (虽然没有测试,可能是错误的)

第一个ORDER BY条件将父母和孩子一起排序;然后第二个确保父母在其子女之前;第三个是在孩子之间进行排序。

此外,它显然只适用于您直接描述的情况,即您有两级层次结构。

【讨论】:

  • 这就是我想要的。谢谢!
  • 在我的测试表中,我没有按顺序添加ABC。我最后添加了A。所以我从这个查询中得到的结果是 B、b1、b2、b3、C、c1、c2、c3、A、a1、a2、a3。但如果这永远不会发生,或者如果主要类别的顺序无趣,那么这当然会起作用。但是,由于主要类别也有一个 display_order 列,因此我将问题解释为该顺序也很重要。
  • @davogotland:确实,我没有注意到主要类别中的display_order。如果这也需要得到尊重,那么您确实需要加入,就像其他答案之一一样。
【解决方案2】:

一个答案已经被接受,但我想无论如何我都会分享我的想法。我也尝试在它们的 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;

【讨论】:

    【解决方案3】:

    听起来与我用相似的父/子层次结构回答的另一个几乎相同,同时将子元素保留在与其对应的父级相同的分组级别...Check this thread

    【讨论】:

      【解决方案4】:

      只要有可能,我就会逐步构建 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 表达式处理该映射。

      【讨论】:

        猜你喜欢
        • 2015-02-14
        • 2020-11-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多