![]() |
как грамотно выбрать дерево из БД?
есть таблица с комментариями, у некоторых комментариев так называемый parent_id - "комментарии на комментарии".
искал решение грамотной выборки без миллиона запросов к бд. нашёл вот это: http://habrahabr.ru/blogs/sql/43955/ там огорчили, что в mysql нет нормальных средств для этого и типа пользуйтесь пхп, и ссылка вот сюда: http://www.codenet.ru/webmast/php/tree.php это понятно - нерациональный говнокод. собственная мысль (сонный мозг уже ниче не соображает): PHP код:
и потом выводим средставми пхп в нужном порядке. |
Совершенно не понял про массив id шников.
Но я как-то переделывал вышеупомянутую ф-цию примерно таким образом (в виде рекурсии). Возможно какие-то ошибки допустил, писал с ходу PHP код:
|
Имхо для таких ситуаций использования join(и не обязательно инер, для той структуры даных вполне можно и left) являеться более рациональным решением чем прибегать к нескольким запросам и тем более создавать какие то непонятные рекурсии на php которые при порядочном объеме данных и частых запросах могут сыграть злую шутку с сервером.l
|
.:EnoT:. думаю вместо intval лучше заюзать is_numeric,так как цитирую
Цитата:
_ttps://forum.antichat.ru/threadnav56756-1-10.html |
по поводу интвал - что за странная проверка?
я всегда использовал if(intval($_GET['s']) > 0) $s = intval($_GET['s']) Енот ты похоже не открывал мою вторую ссылку - я же говорю что рекурсия в данном случае говнокод, потому что плодит запросы. PHP код:
не проще так: PHP код:
ну а как, как его использовать? |
2 Shadow_p1raT не пойму при чем здеся is_numeric() так как у .:EnoT:. в примере идет intval($id) - которая всегда вернет int значения $id даже если оно будет отричательным тоже самое касаеться и is_numeric() оно вернет true даже при отрицатенльном значении $id, но, имхо, ты прав в другом что перед гверей лутче бы проверить данные на то что они являються число(если нам нужно число) и как сказал Дикс что оно больше чем 0, но как я понял .:EnoT:. привел в качестве примера(хотя при чем тут это я не пойму так как вопрос у Дикса немного другого характера).
2 Дикс ну думаю гуглом ты умешь пользоваться не хуже чем я, там полно примеров с использование и описание JOIN в любых вариациях, вот неплохое обьяснения использования JOIN http://www.codinghorror.com/blog/archives/000976.html. |
нужны два запроса:
первый выдирает все нужные комменты с parent_id=null второй все, у которых в parent_id - айдишники уже выбранных. PHP код:
типа вот так: PHP код:
прежде чем копать дальше, хочу узнать - реально ли вообще объединить те два запроса в один? |
В даном примере тебе не нужен JOIN так как у тебя 1 табличка, потому как я понял тебе надо что бы результат выборки одного запроса передовался в другой запрос для это легче и логичней использовать подзапрос, я не пойму что пытаешься зделать, у тебя 2 одинаковых запроса, то есть
select * from comments where parent_id=null limit 0, 10 вы берет все значения из comments parent_id =null а во втором запросе ты делаешь тоже самое select * from comments where parent_id in(список id из первого запроса) то есть фактически дублируешь 1 запрос, пытаешься найти все значения comments у которых id из первого запроса, то есть с parent_id = null(вернее 10 значений), не совсем понятна мне структура данных которые тебе необходимо выбрать. |
PHP код:
PHP код:
|
Как уже отмечали, средств для рекурсивных запросов в мускуле нет, но выбрать два уровня записей из дерева одним обращением к БД выбрать можно. Запрос будет выглядеть так:
Код:
SELECT *Проблему с несколькими обращениями к БД мы решили, теперь остается только придумать как обрабатывать полученные данные. |
Для 2-х уровней Хелиос написал адекватный запрос (в отличии от большинства написанного в этом топике). Если же необходимо большее количество уровней (зачастую неопределенное) впринципе можно использовать хп, но понадобится минимум 2 курсора. Преимуществ здесь будет 2:
1) Сразу возвращаем полный и нужный нам результат 2) Сохраняется план выполнения данных запросов на серваке, что, при правильном подходе, увеличит скорость работы. |
Helios
спасибо, как раз то, что нужно. я не знал что в in() можно передавать запрос. VDShark что такое хп и курсоры? |
Цитата:
|
Цитата:
> что такое хп и курсоры? ХП - сокращение от Хранимые Процедуры. Т.е. код хранящийся на стороне сервера и вызываемый по имени. А курсоры - это, грубо говоря, аналог циклов трационных языков программирования (другими словами - способ перемещения по кортежам и работы с ними, указатель на полученное отношение). Ну это я попытался рассказать попонятнее... Но можешь прочитать об этом в той же википедии (хоть там и не особо расписано) - http://ru.wikipedia.org/wiki/Курсор_(базы_данных) |
Цитата:
|
Цитата:
Подзапрос возвращает ID элементов в корне. А основной запрос делает выборку этих элементов и их потомков. Без подзапроса ты просто этих потомков не найдешь. |
Цитата:
|
а всё-таки есть проблема с таким подходом.
вот мой запрос: PHP код:
а потом уже мы выбираем вложенные комменты к этим комментам. но мне надо выбрать от n до m комментов в подзапросе, т.к. у меня пейджинг. а mysql говорит что её версия (5.0.15-nt) не поддерживает limit в подзапросах.. как это исправить? есть ещё какие-то способы выполнить подзапрос, но с лимитом? |
Ну вобшето я даже и не предполагал на кого то буровить, если это так воспринял то извеняй, а теперь по делу, если тебе несложно покажи ту структуру данных при которых даный запрос будет работать, ибо как ты заметил моей сображалки не хватает, покажи плиз свою.
|
Цитата:
А по делу - если вообще не будет потомков (т.е. у всех записей будет pid=0), тогда вернутся идентичные рзультаты, иначе же будут утеряны родители (если запрос без where pid=0). |
PHP код:
ты и меня смутил. но я понял в чем суть. сначала вложенный запрос выбирает все комментарии первого уровня (как раз лимита на это я и не могу поставить) затем основной запрос выбирает опять комментарии первого уровня (где парент_ид НУЛЛ) - это кстати совсем лишнее И выбирает комментарии второго уровня, у которых парент_ид лежит в области тех ид, что выбраны в самом начале. убираем из основного запроса "WHERE `parent_id` = NULL", и каким-то образом добавляем лимит во вложенный запрос - вот то что необходимо для того, чтобы выбрать только нужные комменты и ВСЕ их подкомменты. |
Дикс, если есть возможность изменить структуру таблицы, тогда советую почитать про nested sets. Этот метод очень хорош для выборки поддерева.
|
Если убрать проверку на `parent_id` = NULL из основного запроса, то ты получишь только комментырии второго уровня.
Подзапрос не выбирает комментарии первого уровня, он только находит их идентификаторы, по которым мы выбираем комменты второго уровня. Как я понял, ты берешь на страницу N комментариев первого уровня и всех их потомков. В таком случае вижу два выхода: Первый из них - выбирать все и брать нужное средствами PHP, что совсем не айс. Потому метод отбрасываем. Второй - все таки разделить на два запроса: Код:
SELECT * FROM `comments` WHERE `parent_id` = NULL AND `t` = '1' LIMIT 0,5Код:
SELECT * Решение не из самых красивых, но это все же не рекурсия - влаживаем все в два запроса. |
Цитата:
|
http://forum.ixbt.com/topic.cgi?id=26:39140
|
| Время: 13:49 |