есть таблица с комментариями, у некоторых комментариев так называемый parent_id - "комментарии на комментарии". искал решение грамотной выборки без миллиона запросов к бд. нашёл вот это: http://habrahabr.ru/blogs/sql/43955/ там огорчили, что в mysql нет нормальных средств для этого и типа пользуйтесь пхп, и ссылка вот сюда: http://www.codenet.ru/webmast/php/tree.php это понятно - нерациональный говнокод. собственная мысль (сонный мозг уже ниче не соображает): PHP: -select comments where parent_id == null $ids = все выбранные ид, через запятую -select comments where parent_id in($ids) фореач comments{ если in_array(текущий ид, $parent_ids) то выбираем к нему все комментарии второго уровня } в результате мы делаем тока два запроса (может можно и один сделать через иннер джоин?) и потом выводим средставми пхп в нужном порядке.
Совершенно не понял про массив id шников. Но я как-то переделывал вышеупомянутую ф-цию примерно таким образом (в виде рекурсии). Возможно какие-то ошибки допустил, писал с ходу PHP: <?php function tree($id, $parent_id=0){ $sql = mysql_query('SELECT * FROM `comments` WHERE `id` = '.intval($id).' AND`parent_id` = '.$parent_id); if($sql && mysql_num_rows($sql)){ while($res = mysql_fetch_object($sql)){ if($res->parent_id) return tree($id, $res->parent_id); else return $res->text; } } } ?>
Имхо для таких ситуаций использования join(и не обязательно инер, для той структуры даных вполне можно и left) являеться более рациональным решением чем прибегать к нескольким запросам и тем более создавать какие то непонятные рекурсии на php которые при порядочном объеме данных и частых запросах могут сыграть злую шутку с сервером.l
.:EnoT:. думаю вместо intval лучше заюзать is_numeric,так как цитирую взято от сюда _ttps:/threadnav56756-1-10.html
по поводу интвал - что за странная проверка? я всегда использовал if(intval($_GET['s']) > 0) $s = intval($_GET['s']) Енот ты похоже не открывал мою вторую ссылку - я же говорю что рекурсия в данном случае говнокод, потому что плодит запросы. PHP: tree($id, $parent_id=false){ $parent_id = $parent_id ? $parent_id : NULL; это ваще че?)) не проще так: PHP: tree($id, $parent_id=NULL){ AkyHa_MaTaTa ну а как, как его использовать?
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: select * from comments where parent_id=null limit 0, 10 select * from comments where parent_id in(список id из первого запроса) можно как-то объединить это в один запрос? типа вот так: PHP: select * from trazh_comment as c1 inner join trazh_comment as c2 on c1.parentid=null or c2.parentid = c1.cid limit 0, 10 выдаёт какую-то хрень с кучей одноименных столбцов. прежде чем копать дальше, хочу узнать - реально ли вообще объединить те два запроса в один?
В даном примере тебе не нужен 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: select * from comments where parent_id=null limit 0, 10 select * from comments where parent_id in(список id из первого запроса) а вот так конкретно это одним запросом: PHP: select * from comments where parent_id=null limit 0, 10 если мне логика не изменяет. Т.е. первый же запрос делает то, что тебе надо получить типо во втором
Как уже отмечали, средств для рекурсивных запросов в мускуле нет, но выбрать два уровня записей из дерева одним обращением к БД выбрать можно. Запрос будет выглядеть так: Code: SELECT * FROM `comments` WHERE `parent_id` = NULL OR `parent_id` IN ( SELECT `id` FROM `comments` WHERE `parent_id` = NULL ) Подзапросом мы вибираем идентификаторы тех элементов, которые не имеют родительских элементов, а основным запросом мы вибираем все те же корневые элементы и все их элементы-потомки. Проблему с несколькими обращениями к БД мы решили, теперь остается только придумать как обрабатывать полученные данные.
Для 2-х уровней Хелиос написал адекватный запрос (в отличии от большинства написанного в этом топике). Если же необходимо большее количество уровней (зачастую неопределенное) впринципе можно использовать хп, но понадобится минимум 2 курсора. Преимуществ здесь будет 2: 1) Сразу возвращаем полный и нужный нам результат 2) Сохраняется план выполнения данных запросов на серваке, что, при правильном подходе, увеличит скорость работы.
Helios спасибо, как раз то, что нужно. я не знал что в in() можно передавать запрос. VDShark что такое хп и курсоры?
Я не вижу смысла выполнения этого запроса, критерии по которым выбераються данные при главном запросе идентичны тем которые идут в подзапросе, в итоге мы получаем тот же результат что и в основном запросе просто лишний раз проходим по таблице.
А если подумать немного? Выполни такие запросы и посмотри результат, м.б. натолкнет на ответ. > что такое хп и курсоры? ХП - сокращение от Хранимые Процедуры. Т.е. код хранящийся на стороне сервера и вызываемый по имени. А курсоры - это, грубо говоря, аналог циклов трационных языков программирования (другими словами - способ перемещения по кортежам и работы с ними, указатель на полученное отношение). Ну это я попытался рассказать попонятнее... Но можешь прочитать об этом в той же википедии (хоть там и не особо расписано) - http://ru.wikipedia.org/wiki/Курсор_(базы_данных)
Запросы разные вообще-то и результаты выполнения их тоже разные, в чем можно убедиться, скормив запрос базе данных. Подзапрос возвращает ID элементов в корне. А основной запрос делает выборку этих элементов и их потомков. Без подзапроса ты просто этих потомков не найдешь.
Видимо данные на которых ты проверял были не учитывающими данную ситуацию... в чем я сильно сомневаюсь. Поэтому необходимо включать соображалку хотя бы иногда, а не безосновательно буровить на людей.
а всё-таки есть проблема с таким подходом. вот мой запрос: PHP: SELECT * FROM comment WHERE tid =1 AND parentid IS NULL OR parentid IN ( SELECT cid FROM comment WHERE tid =1 AND parentid IS NULL ORDER BY ctime ASC ) ORDER BY ctime ASC LIMIT 0 , 10 таким образом: сначала выполняется подзапрос. он возвращает ВСЕ id у которых tid=1 - ну типа комменты относятся к определенной теме. а потом уже мы выбираем вложенные комменты к этим комментам. но мне надо выбрать от n до m комментов в подзапросе, т.к. у меня пейджинг. а mysql говорит что её версия (5.0.15-nt) не поддерживает limit в подзапросах.. как это исправить? есть ещё какие-то способы выполнить подзапрос, но с лимитом?
Ну вобшето я даже и не предполагал на кого то буровить, если это так воспринял то извеняй, а теперь по делу, если тебе несложно покажи ту структуру данных при которых даный запрос будет работать, ибо как ты заметил моей сображалки не хватает, покажи плиз свою.
Извиняю, надеюсь ты действительно не имел ввиду ничего дурного А по делу - если вообще не будет потомков (т.е. у всех записей будет pid=0), тогда вернутся идентичные рзультаты, иначе же будут утеряны родители (если запрос без where pid=0).