#sql
#sql
Вопрос:
Я пытаюсь реализовать таблицу категорий. Упрощенное описание таблицы выглядит следующим образом
id -- name -- parent_id
предполагая, что образец данных типа
id - name - parent_id
1 test1 null
2 test2 null
3 test3 null
4 test4 1
5 test5 4
6 test6 2
7 test7 1
Я изо всех сил пытаюсь придумать sql-запрос, который вернет набор записей в следующем порядке
id - name - parent_id
1 test1 null
4 test4 1
5 test5 4
7 test7 1
2 test2 null
6 test6 2
3 test3 null
В основном дочерние элементы возвращаются после их родительского элемента.
———————— РЕШАЕТСЯ С ПОМОЩЬЮ LINQ / рекурсии в коде ————————-
Не совсем sql-решение, но в конечном итоге оно работает.
Комментарии:
1. Я не думаю, что есть достаточная спецификация. Кажется произвольным, почему
test1
был родительским раньшеtest2
, илиtest3
если уж на то пошло.2. Возможно, я упускаю суть. Но я не вижу связи между данными выборки и порядком ожидаемых данных. (Уже поздно, поэтому, если я упускаю очевидное, я приношу извинения)
3. test1 должен быть перед test4, если он хочет, чтобы он был упорядочен в соответствии с родительским отношением, из этого следует, что test2, являющийся следующим идентификатором в упорядоченном списке, будет следующим родительским элементом в результатах
4. С помощью одного запроса? нет, вы не можете.
5. Это иерархический запрос, и такие вещи, как известно, трудно кодировать — будь то в SQL или любой другой системе. Существуют (совместимые со стандартом) диалекты SQL, которые поддерживают предложение WITH и предложение WITH RECURSIVE. Существуют другие диалекты, которые поддерживают предложения CONNECT BY . Работа с 3-уровневой иерархией, как в вопросе, не слишком сложна; расширение ее до 4 уровней также не так уж плохо. Одна из трудностей заключается в том, чтобы знать, сколько уровней вам нужно поддерживать, и писать SQL для каждого такого уровня — отсюда необходимость в рекурсивных решениях.
Ответ №1:
Основываясь на том, что вы пытаетесь сделать с запросом, вам не нужно сортировать его таким образом. Вам просто нужно убедиться, что сначала созданы родительские элементы. Итак, запустите свой запрос, отсортированный по родительскому идентификатору, поместите результат в массив и выполните цикл по этому массиву. На каждой итерации выполняйте проверку, чтобы убедиться, что parent существует, если у него есть parent. Если родительский элемент не существует, просто переместите этот элемент в конец массива и перейдите к следующему на данный момент у вас должно получиться всего несколько перемещаемых обращений, чтобы он оставался достаточно эффективным.
Ответ №2:
Что я всегда делал в прошлом, так это разбивал базу данных на следующие части (хотя я не лучший специалист по SQL, поэтому для вас могут быть какие-то другие решения).
categories
- category_id | int(11) | Primary Key / Auto_Increment
..
..
sub_categories
- sub_category_id | int(11) | Primary Key / Auto_Increment
- category_id | int(11) | Foreign Key to categories table
..
..
Ответ №3:
Вот что я бы сделал:
SELECT id, name, parent_id, (CASE WHEN COALESCE(parentid,0)=0 THEN id ELSE (parentid '.' id)) as orderid
FROM table
ORDER BY (CASE WHEN COALESCE(parentid,0)=0 THEN id ELSE (parentid '.' id))
Это должно создать новый столбец с именем orderid, в котором родительский идентификатор совпадает с идентификатором (1.4, 4.5 и т.д.) Для столбцов, в которых родительский идентификатор равен null, он будет указывать только идентификатор. Таким образом, вы получите порядок как 1, 1.4, 4, 4.5 и т.д.
Пожалуйста, проверьте код, поскольку я написал это на лету без тестирования. Это должно быть близко.
Ответ №4:
Приведенный ниже запрос выполняется путем добавления дополнительного order_parent
столбца, который содержит либо родительский идентификатор, либо идентификатор строки, в зависимости от того, является ли он родительским. Затем он просто сортирует сначала по order_parent
идентификатору, чтобы сгруппировать их вместе, затем по parent_id
для сортировки null
s (фактических родителей) сверху.
Две вещи:
- Здесь есть еще один столбец, который вы изначально хотели, поэтому просто игнорируйте его.
- В случае, если ваша база данных возвращает
nulls
parent_id последним, добавьтеDESC
.
Кстати, хороший вопрос!
SELECT id,
name,
parent_id,
(
case
when parent_id is null then id
else parent_id
end
) AS order_parent
FROM myTable
ORDER BY order_parent, parent_id
Комментарии:
1. Вы выполняли этот запрос? Дочерние элементы сортируются, но внуки (id = 5) заканчиваются последними
2. Ах, внуки. Вполне. Я этого не заметил.
3. да, я пытался запустить его. Похоже, что это вот-вот сработает. но на самом деле это не работает. Для простоты (чтобы избежать нулей) я скопировал идентификаторы в поля родительского идентификатора для узлов, у которых нет родительского элемента.
4. Я не могу придумать способ согласовать это, чтобы работать на нескольких уровнях поколений. Даже если у вас есть корневой родительский элемент в
order_parent
, у вас не было бы чего сортировать, чтобы получить внуков в правильном порядке.5. тем не менее, ценю усилия. Вероятно, в конечном итоге я сделаю это с помощью кода. 🙁