SQL nested order by?

前端 未结 4 1533
渐次进展
渐次进展 2020-12-19 13:13

I\'m sure that this has been asked before, but I don\'t know what to call it exactly to find the answer.

I have a table of categories and sub categories. They each

相关标签:
4条回答
  • 2020-12-19 14:00

    Something like this might maybe work:

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

    but since it can't use an index, it'll be slow. (Didn't test though, might be wrong)

    The first ORDER BY condition sorts parents and children together; then the second one ensures the parent precedes its children; the third sorts the children among themselves.

    Also, it will obviously work only in the case you directly described, where you have a two-level hierarchy.

    0 讨论(0)
  • 2020-12-19 14:02

    an answer has already been accepted, but i thought i would share my thoughts on this anyways. i tried to sort the main categories after their display_order column as well. here's my table

    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)
    

    as you see, i have taken great care to add the categories in a none linear order :)

    my query:

    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;
    
    0 讨论(0)
  • 2020-12-19 14:02

    Whenever possible, I build SQL incrementally, not least because it gives me the option of testing as I go.

    The first thing we need to be able to do is identify the top-level categories:

     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;
    

    Now we need to join that with the categories and subcategories to get the result:

    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;
    

    The join condition is unusual but should work; it collects rows where the parent ID is the same as the current category ID, or rows where the parent ID is 0 but the category ID is the same. The ordering is then almost trivial - except that when you are dealing with the sub-category ordering, you want the parent item at the front of the list. The CASE expression handles that mapping.

    0 讨论(0)
  • 2020-12-19 14:10

    Sounds almost identical to another I've answered with similar parent/child hierarchy while retaining child elements at same grouped level as its corresponding parent...Check this thread

    0 讨论(0)
提交回复
热议问题