Вложенные запросы MySQL, как выбрать более одной строки

SELECT id, FIO, parent_id
FROM users
WHERE parent_id =
(
    SELECT id
    FROM users
    WHERE parent_id =
    (
        SELECT id
        FROM users
        WHERE id = 16
    )
)

Итак, здесь я создаю иерархическое дерево, сначала выбирая корневой родительский элемент, затем дочерний элемент и так далее до 24-го уровня глубины.

Вопрос: как выбрать более одного столбца из внутренних запросов?

Потому что мне нужно, чтобы другие поля строк отображали информацию, например: name, surname, age

Похоже, я могу получить только эти столбцы строк во внешнем запросе (самом верхнем).

P.S.: Я не хочу использовать соединения, потому что они генерируют повторяющиеся поля.

Есть ли решение?


person Mister PHP    schedule 09.07.2012    source источник
comment
Соединения генерируют повторяющиеся поля, если вы укажете, что они должны отображаться в предложении select. PS. 24 уровня глубины выглядят как огромный, не поддающийся обработке запрос, который окупается, если вы используете рекурсию для получения данных до тех пор, пока parent_id не станет нулевым. Просто говорю   -  person Alfabravo    schedule 10.07.2012
comment
Пожалуйста, предоставьте вашей аудитории объяснение вашего намерения такого вложенного (24 раза?) запроса. Что вы делаете? Хотите найти всех потомков, которые находятся в 24 шагах от пользователя? (все пра-пра-пра-пра-.....-дети?)   -  person Kaii    schedule 10.07.2012
comment
stackoverflow.com/questions/11385250 / - вот причина   -  person Mister PHP    schedule 10.07.2012
comment
получение полного иерархического дерева с несколькими родителями в одном запросе и одним набором результатов без какой-либо итерации невозможно, насколько мне известно. Как вообще должен выглядеть результат?   -  person Kaii    schedule 10.07.2012
comment
stackoverflow.com/questions/11385250 / - здесь я написал о том, как это должно выглядеть   -  person Mister PHP    schedule 10.07.2012
comment
вы можете помочь мне двумя способами: 1) помочь мне сделать лучший запрос, который выберет 24 статических уровня глубины в списке моделей смежности, 2) помочь мне отобразить запрос, который у меня есть на данный момент, в php (используя codeigniter), пожалуйста помоги!!!   -  person Mister PHP    schedule 10.07.2012
comment
мой запрос сумасшедший, поэтому вам нужно найти другое решение   -  person Kaii    schedule 10.07.2012


Ответы (5)


Вы можете выполнить итерацию на стороне SQL, используя переменные запроса MySQL. Это вернет все дочерние элементы со всеми данными одного родительского узла без повторения себя (и, следовательно, без ограничения глубины вашего дерева)

что-то вроде этого: (500 - это идентификатор родителей для начала)

SELECT
  id,
  parent_id, 
  name, 
  '0' as depth, 
  @tree_ids := id AS foo
FROM 
   tree,
  (SELECT @tree_ids := '', @depth := -1) vars
WHERE id = 500
UNION
SELECT 
  id,
  parent_id,
  name,
  @depth := IF(parent_id = 500, 1, @depth + 1) AS depth,
  @tree_ids := CONCAT(id, ',', @tree_ids) AS foo
FROM 
  tree 
WHERE FIND_IN_SET(parent_id, @tree_ids) OR parent_id = 500

См. рабочий пример на SQLfiddle.

Обратите внимание, что это дает очень плохую производительность для больших наборов данных, потому что MySQL не будет использовать ваши индексы, а вместо этого выполнит полное сканирование таблицы. (я не понимаю, почему он не использует индексы, так оно и есть. Если у кого-то есть совет или объяснение проблемы индексации, пожалуйста, прокомментируйте!)

person Kaii    schedule 09.07.2012
comment
похоже, что mysql не лучшая база данных для таких проблем? - person Mister PHP; 10.07.2012
comment
Просто из интереса я опубликовал еще один вопрос, почему он не использует ИНДЕКСы: переменные запроса, не использующие индексы"> stackoverflow.com/questions/11403768/ - person Kaii; 10.07.2012
comment
я использовал ваше решение, и у меня есть вопрос, почему корневой родитель имеет глубину 2, а дочерние элементы имеют глубину 1, скопировал ваш код и отредактировал идентификатор в моем - person Mister PHP; 10.07.2012
comment
может быть, потому что parent_id не равен нулю и принадлежит родителю более высокого уровня? - person Mister PHP; 10.07.2012
comment
Этот запрос на самом деле является сумасшедшим, когда идентификаторы не являются последовательными. - person Kaii; 10.07.2012
comment
Вау, это работает))))))), но один вопрос, почему он возвращает BLOB - 0, BLOB - 5B и т.д... в строках parent_id и name - person Mister PHP; 10.07.2012
comment
это происходит в моем phpmyadmin, поэтому, как я вижу, он возвращает нецелые числа - person Mister PHP; 10.07.2012

= сравнения работают только с одним значением. Вы можете использовать in для сравнения с несколькими значениями:

SELECT ...
FROM yourtable
WHERE somefield IN (select somevalue from othertable);
person Marc B    schedule 09.07.2012
comment
см. это, пожалуйста, stackoverflow.com/ вопросы/11385250/ - person Mister PHP; 10.07.2012
comment
я думаю, что это будет сложнее, когда у меня будет 24 уровня глубины... или вы можете показать мне, как это сделать, скажем, на 5-10 уровнях глубины? - person Mister PHP; 10.07.2012
comment
Для произвольной глубины вложенности вам лучше переключиться на БД, которая позволяет выполнять рекурсивные запросы, например. Postgres и выбор по предыдущим материалам. Вы можете подделать это в MySQL с помощью (выходя из памяти) «модели набора смежности», но я никогда не пытался с этим справиться. - person Marc B; 10.07.2012
comment
так что похоже, что Postgres лучше, чем MySQL для этих проблем? - person Mister PHP; 10.07.2012

Хранить иерархические данные в mysql и получать их не так просто.

Посмотрите на это: https://stackoverflow.com/a/4346009/9094

Вам потребуется больше данных для работы.

person databyss    schedule 09.07.2012
comment
stackoverflow.com/questions/11385250 / - посмотрите это, пожалуйста - person Mister PHP; 10.07.2012

Похоже, ваши отношения с БД настроены на MPTT, вот хороший пост в блоге, объясняющий, как запрашивать данные mysql MPTT http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

Взгляните на пример полного дерева Получение полного дерева в целом можно сделать с помощью соединений.

person Abhishek Dujari    schedule 09.07.2012
comment
см. это, пожалуйста, stackoverflow.com/ вопросы/11385250/ - person Mister PHP; 10.07.2012
comment
отличный! похоже, ваша проблема была решена, я был совершенно не в том направлении :) - person Abhishek Dujari; 10.07.2012
comment
Я прочитал эту статью и выбрал модель смежного списка, но теперь у меня проблема с ее рендерингом в php, не могли бы вы дать мне небольшой пример того, как это сделать? stackoverflow.com/questions/11385250 / - это мой вопрос, пожалуйста, ответьте там - person Mister PHP; 10.07.2012
comment
нет, это не решено :(, эти ответы мне не помогли, один из этих ответов заключался в использовании подзапросов, поэтому я спрашиваю об этом здесь, до того, как я использовал самообъединения и не визуализировал дерево в php, поэтому, пожалуйста, помогите, stackoverflow.com/questions/11385250/ — здесь можно ответить - person Mister PHP; 10.07.2012

Я не уверен на 100%, правильно ли я понял, что вы имеете в виду, но если вы хотите выбрать все столбцы отдельно из таблицы в подзапросе...

col1, col2, col3, col4

вам понадобится для каждого столбца один подвыбор, который всегда соответствует одному и тому же WHERE. Пример:

`SELECT * FROM main_table,
(SELECT col1 FROM inner_table WHERE inner_table.some_column=main_table.some_column),
(SELECT col2 FROM inner_table WHERE inner_table.some_column=main_table.some_column), ...`
person Chris    schedule 09.07.2012
comment
см. этот раздел stackoverflow.com/ вопросы/11385250/ - person Mister PHP; 10.07.2012
comment
Я не знаю, правильно ли сделать лучший выбор в этом случае? и будет очень хорошо, если вы покажете мне небольшой пример того, как отобразить его в php, сделав этот запрос на выборку, скажем, на 5-10 уровнях (на самом деле у меня будет 24 статических уровня, это не изменится) - person Mister PHP; 10.07.2012