SQL вложенный порядок по? - PullRequest
4 голосов
/ 14 января 2012

Я уверен, что об этом уже спрашивали, но я не знаю, как именно это назвать, чтобы найти ответ.

У меня есть таблица категорий и подкатегорий. У каждого из них есть идентификатор и идентификатор родителя. Если это категория верхнего уровня, родительский идентификатор равен 0. Для подкатегорий родительский идентификатор установлен на идентификатор категории его родителя.

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 ]

8 голосов
/ 14 января 2012

Нечто подобное может работать:

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

но поскольку он не может использовать индекс, он будет медленным. (Не проверял, хотя, может быть не так)

Первое ORDER BY условие сортирует родителей и детей вместе; затем второй гарантирует, что родитель предшествует своим детям; третий сортирует детей между собой.

Кроме того, очевидно, что он будет работать только в случае, который вы прямо описали, когда у вас есть двухуровневая иерархия.

1 голос
/ 14 января 2012

ответ уже принят, но я подумал, что все равно поделюсь своими мыслями по этому поводу.я попытался отсортировать основные категории после их столбца 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;
0 голосов
/ 14 января 2012

По возможности, я строю 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;

Условие соединения необычное, но должно работать; он собирает строки, в которых идентификатор родителя совпадает с идентификатором текущей категории, или строки, в которых идентификатор родителя равен 0, но идентификатор категории совпадает. Порядок в этом случае почти тривиален - за исключением того, что когда вы имеете дело с упорядочением подкатегории, вы хотите, чтобы родительский элемент был в начале списка. Выражение CASE обрабатывает это отображение.

0 голосов
/ 14 января 2012

Звучит почти идентично другому, на который я ответил аналогичной родительской / дочерней иерархией, сохраняя дочерние элементы на том же сгруппированном уровне, что и соответствующий родительский элемент ... Проверить эту тему

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...