2015-07-09 4 views
0

Это расширение от another question I just asked. Я узнал, как правильно написать SQL-запрос, чтобы получить желаемый результат, который мне нужен. Но когда я попытался применить его к моему фактическому использованию, я нашел что-то еще, что мне нужно.Добавить child rank to SQL result

Это упрощенная версия таблицы, у меня есть:

+-----+-------------+-----------+ 
| id | name  | parent_id | 
+-----+------------+-----------+ 
| 1 | Bob  | 3   | 
| 2 | John  | 5   | 
| 3 | Larry  | 4   | 
| 4 | Kevin  | 0   | 
| 5 | Kyle  | 0   | 
| 6 | Jason  | 5   | 
| 7 | Mildred | 4   | 
| 8 | Mabel  | 6   | 
| 9 | Amber  | 4   | 
| 10 | Devon  | 5   | 
| 11 | Zack  | 0   | 
| 12 | Alfred  | 11  | 
| 13 | Robert  | 11  | 
| 14 | Keith  | 11  | 
+----+-------------+-----------+ 

(я добавил несколько больше, так как мой последний вопрос, просто так есть больше примеров) Теперь я хотел, чтобы иметь возможность получить списки родителей, детей и внуков. Вот запросы, которые я нашел, чтобы получить те:

Бабушки

SELECT name FROM people WHERE parent_id = 0 

Дети

SELECT c.name 
FROM people p 
JOIN people c ON c.parent_id = p.id 
WHERE p.parent_id = 0 

И внуки

SELECT gc.name 
FROM people p 
JOIN people c ON c.parent_id = p.id 
JOIN people gc ON gc.parent_id = c.id 
WHERE p.parent_id = 0 

Я пытаюсь выяснить что-то для детей, поэтому я оставлю остальных на данный момент. Этот запрос выше для детей дает следующий результат:

+---------+ 
| name | 
+---------+ 
| John | 
| Larry | 
| Jason | 
| Mildred | 
| Amber | 
| Devon | 
| Alfred | 
| Robert | 
| Keith | 
+---------+ 

это хорошо, но мне нужно заказать первый в алфавитном порядке первого родителем, то второй ребенком. Так что я добавить ORDER BY на мой запрос:

SELECT c.name 
FROM people p 
JOIN people c ON c.parent_id = p.id 
WHERE p.parent_id = 0 
ORDER BY p.name, c.name 

Который дает мне:

+---------+ 
| name | 
+---------+ 
| Amber | 
| Larry | 
| Mildred | 
| Devon | 
| Jason | 
| John | 
| Alfred | 
| Keith | 
| Robert | 
+---------+ 

Хорошо. Но теперь проблема в том, что я также хотел бы включить родителей в этот список, прямо вверху, где находятся их дети. Кроме того, я хотел бы каким-то образом показать, является ли результат родителем или дочерним. Поэтому я думал о другом столбце под названием Rank, который имел бы значения 1 или 2, чтобы указать родительский или дочерний. Таким образом, это результат, который я хочу вернуть:

+--------+------+ 
| name | rank | 
+--------+------+ 
| Kevin | 1 | 
| Amber | 2 | 
| Larry | 2 | 
| Mildred| 2 | 
| Kyle | 1 | 
| Devon | 2 | 
| Jason | 2 | 
| John | 2 | 
| Zack | 1 | 
| Alfred | 2 | 
| Keith | 2 | 
| Robert | 2 | 
+--------+------+ 

Это имеет смысл? Какой запрос я могу использовать для получения этого результата?

+0

Если он работает для вас: Это проще, чтобы отобразить родительский рядом с ребенком в отдельной колонке. Вы бы просто добавили «p.name как родительский» и получили свои результаты. –

+1

Ваши три примера запросов, чтобы получить бабушек и дедушек, детей и внуков, ясно демонстрируют, как быстро растет сложность, когда дело касается графических структур. По этой причине я настоятельно рекомендую вам взглянуть на такие технологии, как графические базы данных, такие как neo4j – Jacobian

+0

@NorbertvanNobelen Хорошо, спасибо. Это работает. Но мне также нужно включить родителей в список имен. Как я мог это сделать? И для этих элементов в столбце «родители» я бы просто хотел, чтобы это было «NULL» – eshellborn

ответ

1

Try с этим:

SELECT name, 1 as rank FROM people WHERE parent_id = 0 
UNION 
SELECT child.name AS name, 2 AS rank 
FROM people AS parent, people AS child 
WHERE child.parent_id = parent.id AND parent.parent_id = 0 
ORDER BY name; 

С результатом:

+---------+------+ 
| name | rank | 
+---------+------+ 
| Jason | 2 | 
| John | 2 | 
| Kevin | 1 | 
| Kyle | 1 | 
| Larry | 2 | 
| Mildred | 2 | 
+---------+------+ 

И добавить внуков, с rank = 3:

SELECT name, 1 as rank FROM people WHERE parent_id = 0 
UNION 
SELECT child.name AS name, 2 AS rank 
FROM people AS parent, people AS child 
WHERE child.parent_id = parent.id AND parent.parent_id = 0 
UNION 
SELECT grandchild.name AS name, 3 AS rank 
FROM people AS grandparent, people AS parent, people 
AS grandchild WHERE grandchild.parent_id = parent.id 
AND parent.parent_id = grandparent.id 
ORDER BY rank,name; 

С результатом:

+---------+------+ 
| name | rank | 
+---------+------+ 
| Bob  | 3 | 
| Jason | 2 | 
| John | 2 | 
| Kevin | 1 | 
| Kyle | 1 | 
| Larry | 2 | 
| Mabel | 3 | 
| Mildred | 2 | 
+---------+------+ 

EDIT

Теперь сортируются, как вы просили, однако, как вы можете видеть, есть дополнительный, но в конце концов скрыт, колонок Family_head:

SELECT T.Name, T.Rank FROM (SELECT name, 1 as Rank, Name AS Family_Head FROM people WHERE parent_id = 0 
UNION 
SELECT child.name AS Name, 2 AS Rank, 
(SELECT p.name FROM people AS p WHERE child.parent_id = p.id) as Family_Head 
FROM people AS parent, people AS child 
WHERE child.parent_id = parent.id AND parent.parent_id = 0 
ORDER BY Family_head, Rank, Name) AS T; 

Результат:

+---------+------+-------------+ 
| name | Rank | Family_Head | 
+---------+------+-------------+ 
| Kevin | 1 | Kevin  | 
| Amber | 2 | Kevin  | 
| Larry | 2 | Kevin  | 
| Mildred | 2 | Kevin  | 
| Kyle | 1 | Kyle  | 
| Devon | 2 | Kyle  | 
| Jason | 2 | Kyle  | 
| John | 2 | Kyle  | 
| Zack | 1 | Zack  | 
| Alfred | 2 | Zack  | 
| Keith | 2 | Zack  | 
| Robert | 2 | Zack  | 
+---------+------+-------------+ 
+0

Ницца. Это хорошо. Единственное, что упорядочение неверно. Мне нужен заказ, о котором я упоминал выше, показать первый родительский алфавит, затем все его дочерние элементы в алфавитном порядке, затем второй родитель и т. Д. Я попытался добавить ORDER BY parent.name, child.name; но это дало ошибку – eshellborn

+0

@eshellborn try with 'ORDER BY rank, name;' он должен дать вам желаемый результат –

+0

Это не работает, мне нужно, чтобы заказ был таким же, как указано выше в моем сообщении http://sqlfiddle.com/#! 9/ed315/22 – eshellborn

1

Тип структуры, с которой вы работаете, скорее всего будет гораздо легче справиться в базе данных графов или реляционной базе данных с лучшей поддержкой рекурсивных запросов t han MySQL, но с помощью оператора union all вместе с арифметикой можно добиться результата, который примерно соответствует тому, что вы ищете.

SELECT Generation, Name, Rank 
FROM (

    SELECT 'Grand parent' AS Generation, id*1000 level, name, 1 as rank 
    FROM people WHERE parent_id = 0 

    UNION ALL 

    SELECT 'Parent', p.id*1000 + 1*100, c.name, 2 as rank 
    FROM people p 
    JOIN people c ON c.parent_id = p.id 
    WHERE p.parent_id = 0 

    UNION ALL 

    SELECT 'Grand child', p.id*1000+1*100+gc.id, gc.name, 3 as rank 
    FROM people p 
    JOIN people c ON c.parent_id = p.id 
    JOIN people gc ON gc.parent_id = c.id 
    WHERE p.parent_id = 0 

) a 
ORDER BY level, name; 
-- WHERE Rank <= 2 -- add this or remove the last union to remove grand children 

дает результат, как:

| Generation |  name | rank | 
|--------------|----------|------| 
| Grand parent | Kevin | 1 | 
|  Parent | Amber | 2 | 
|  Parent | Larry | 2 | 
|  Parent | Mildred | 2 | 
| Grand child | Bob  | 3 | 
| Grand parent | Kyle  | 1 | 
|  Parent | Devon | 2 | 
|  Parent | Jason | 2 | 
|  Parent | John  | 2 | 
| Grand child | Mabel | 3 | 
| Grand parent | Zack  | 1 | 
|  Parent | Alfred | 2 | 
|  Parent | Keith | 2 | 
|  Parent | Robert | 2 | 

Sample SQL Fiddle

+0

Это предположение невозможно.Это не должно быть слишком сложно, мне просто нужно каким-то образом отличить родителей от детей. И важно, чтобы это было в том порядке, в котором я выше. Я не могу изменить структуру базы данных, поскольку она встроена в наши cms. – eshellborn

+0

@eshellborn. Хорошо, позвольте мне подумать минуту – jpw

+0

@eshellborn Посмотрите сейчас, пожалуйста. Я включил поколения внуков, но если вы не хотите, чтобы просто комментировать последний союз и запрос. – jpw