ANTICHAT.XYZ    VIDEO.ANTICHAT.XYZ    НОВЫЕ СООБЩЕНИЯ    ФОРУМ  
Баннер 1   Баннер 2
Antichat снова доступен.
Форум Antichat (Античат) возвращается и снова открыт для пользователей. Здесь обсуждаются безопасность, программирование, технологии и многое другое. Сообщество снова собирается вместе.
Новый адрес: forum.antichat.xyz
Вернуться   Форум АНТИЧАТ > Программирование > PHP, PERL, MySQL, JavaScript
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

как грамотно выбрать дерево из БД?
  #1  
Старый 06.02.2009, 23:02
Аватар для Дикс
Дикс
Познавший АНТИЧАТ
Регистрация: 16.04.2006
Сообщений: 1,488
Провел на форуме:
2209675

Репутация: 537


Отправить сообщение для Дикс с помощью ICQ
По умолчанию как грамотно выбрать дерево из БД?

есть таблица с комментариями, у некоторых комментариев так называемый 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)
   
то выбираем к нему все комментарии второго уровня


в результате мы делаем тока два запроса (может можно и один сделать через иннер джоин?)
и потом выводим средставми пхп в нужном порядке.
 
Ответить с цитированием

  #2  
Старый 07.02.2009, 01:05
Аватар для .:EnoT:.
.:EnoT:.
Постоянный
Регистрация: 29.05.2007
Сообщений: 852
Провел на форуме:
4832771

Репутация: 1916


По умолчанию

Совершенно не понял про массив 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;
        }
    }
}           

?>

Последний раз редактировалось .:EnoT:.; 20.03.2009 в 19:34.. Причина: Исправил)
 
Ответить с цитированием

  #3  
Старый 07.02.2009, 04:24
Аватар для AkyHa_MaTaTa
AkyHa_MaTaTa
Постоянный
Регистрация: 19.03.2007
Сообщений: 684
Провел на форуме:
3152874

Репутация: 1020


Отправить сообщение для AkyHa_MaTaTa с помощью ICQ
По умолчанию

Имхо для таких ситуаций использования join(и не обязательно инер, для той структуры даных вполне можно и left) являеться более рациональным решением чем прибегать к нескольким запросам и тем более создавать какие то непонятные рекурсии на php которые при порядочном объеме данных и частых запросах могут сыграть злую шутку с сервером.l
 
Ответить с цитированием

  #4  
Старый 07.02.2009, 06:37
Аватар для Shadow_p1raT
Shadow_p1raT
Участник форума
Регистрация: 09.03.2008
Сообщений: 193
Провел на форуме:
2140897

Репутация: 267
Отправить сообщение для Shadow_p1raT с помощью ICQ
По умолчанию

.:EnoT:. думаю вместо intval лучше заюзать is_numeric,так как цитирую
Цитата:
У intval() есть интересная особенность - она возвращает TRUE если первой в аргументе содержится хотя бы одна цифра.
И у разработчиков тоже есть интересная особенность =)) -- они периодически используют intval()/(int) в логичесих условиях,
допуская непростительные ошибки.
Ведь наличие цифр в строке вовсе не гарантирует отсутствие других символов.

Пример:
/index.php?id=1'"qwerty
PHP код:
$id=$_GET['id']; 
    if(
intval($id) && (int)$id
     { 
      
sql_query("select $id from table_name"); 
     } 
     else die(
'Id not integer!'); 
Несмотря на кажущуюся незначительность баги, встречается она в диком тырнете достаточно регулярно.
Для безопасного сравнения используйте is_numeric()
взято от сюда
_ttps://forum.antichat.ru/threadnav56756-1-10.html
 
Ответить с цитированием

  #5  
Старый 07.02.2009, 08:16
Аватар для Дикс
Дикс
Познавший АНТИЧАТ
Регистрация: 16.04.2006
Сообщений: 1,488
Провел на форуме:
2209675

Репутация: 537


Отправить сообщение для Дикс с помощью ICQ
По умолчанию

по поводу интвал - что за странная проверка?
я всегда использовал 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
ну а как, как его использовать?

Последний раз редактировалось Дикс; 07.02.2009 в 09:12..
 
Ответить с цитированием

  #6  
Старый 07.02.2009, 17:14
Аватар для AkyHa_MaTaTa
AkyHa_MaTaTa
Постоянный
Регистрация: 19.03.2007
Сообщений: 684
Провел на форуме:
3152874

Репутация: 1020


Отправить сообщение для AkyHa_MaTaTa с помощью ICQ
По умолчанию

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.
 
Ответить с цитированием

  #7  
Старый 07.02.2009, 18:14
Аватар для Дикс
Дикс
Познавший АНТИЧАТ
Регистрация: 16.04.2006
Сообщений: 1,488
Провел на форуме:
2209675

Репутация: 537


Отправить сообщение для Дикс с помощью ICQ
По умолчанию

нужны два запроса:
первый выдирает все нужные комменты с parent_id=null
второй все, у которых в parent_id - айдишники уже выбранных.
PHP код:
select from comments where parent_id=null limit 010
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 010 
выдаёт какую-то хрень с кучей одноименных столбцов.
прежде чем копать дальше, хочу узнать - реально ли вообще объединить те два запроса в один?
 
Ответить с цитированием

  #8  
Старый 07.02.2009, 18:49
Аватар для AkyHa_MaTaTa
AkyHa_MaTaTa
Постоянный
Регистрация: 19.03.2007
Сообщений: 684
Провел на форуме:
3152874

Репутация: 1020


Отправить сообщение для AkyHa_MaTaTa с помощью ICQ
По умолчанию

В даном примере тебе не нужен 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 значений), не совсем понятна мне структура данных которые тебе необходимо выбрать.
 
Ответить с цитированием

  #9  
Старый 07.02.2009, 18:59
Аватар для Pashkela
Pashkela
Динозавр
Регистрация: 10.01.2008
Сообщений: 2,841
Провел на форуме:
9220514

Репутация: 3338


Отправить сообщение для Pashkela с помощью ICQ
По умолчанию

PHP код:
select from comments where parent_id=null limit 010 
select 
from comments where parent_id in(список id из первого запроса
а вот так конкретно это одним запросом:

PHP код:
select from comments where parent_id=null limit 010 
если мне логика не изменяет. Т.е. первый же запрос делает то, что тебе надо получить типо во втором
 
Ответить с цитированием

  #10  
Старый 07.02.2009, 20:14
Аватар для Helios
Helios
Постоянный
Регистрация: 14.01.2007
Сообщений: 459
Провел на форуме:
1469995

Репутация: 589
Отправить сообщение для Helios с помощью ICQ
По умолчанию

Как уже отмечали, средств для рекурсивных запросов в мускуле нет, но выбрать два уровня записей из дерева одним обращением к БД выбрать можно. Запрос будет выглядеть так:

Код:
SELECT *
FROM `comments`
WHERE `parent_id` = NULL
OR `parent_id` IN (
    SELECT `id` FROM `comments` WHERE `parent_id` = NULL
)
Подзапросом мы вибираем идентификаторы тех элементов, которые не имеют родительских элементов, а основным запросом мы вибираем все те же корневые элементы и все их элементы-потомки.

Проблему с несколькими обращениями к БД мы решили, теперь остается только придумать как обрабатывать полученные данные.
 
Ответить с цитированием
Ответ



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
F.A.Q по Пранку Nightmarе Статьи 43 28.03.2010 10:55
FAQ по выделенным серверам †Romi4† Авторские статьи 4 31.08.2009 16:19
Социальная инженерия. Профессиональное программирование. Последовательный взлом dinar_007 Болталка 15 23.12.2008 12:30



Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT.XYZ