ЖЖ подобные комменты

Работа VB и СУБД (Access, MSSQL, MySQL, Oracle и пр.)
Правила форума
При создании новой темы не забывайте указывать используемую СУБД.
FaKk2
El rebelde gurú
El rebelde gurú
Аватара пользователя
 
Сообщения: 2031
Зарегистрирован: 09.03.2003 (Вс) 22:10
Откуда: Los Angeles

ЖЖ подобные комменты

Сообщение FaKk2 » 16.08.2005 (Вт) 8:37

Хочу сделать комментарии в сайту на подобие ЖЖ, т.е. чтоб можно было отвечать на какой то определенный коммент и таким образом создавать треды.

Изначально, пораскинув мозгами я пришел к следующей структуре:

Код: Выделить всё
comments
------------
id
publication_id
content
parent_id
has_childs


Где parent_id - ид коммента родителя, а has_childs, по моей задумке должно играть роль остановки рекурсии. Ведь по идее кол-во комментов и тредов к ним бесконечное количество. Т.е. рекурсивная ф-ция ищет детей для текущего коммента до тех пор пока has_childs равно 1.

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

Код: Выделить всё
Array
(
    [0] => Array
        (
            [0] => Array
                (
                    [id] => 1
                    [content] => test
                    [child] => Array
                        (
                            [0] => Array
                                (
                                    [id] => 2
                                    [content] => мама
                                    [publication_id] => 1
                                )
                             [1] => Array
                                (
                                    [id] => 3
                                    [content] => папа
                                    [publication_id] => 1
                                )
                        )
                )
            [1] => Array
                (
                    [id] => 4
                    [content] => баба
                    [publication_id] => 1
                )
        )


Конечно, ограничений на вложения не должно быть. На данный момент, я делаю эту конструкцию в два этапа:

1.
Код: Выделить всё
SELECT * FROM comments WHERE parent_id=0
Т.е. беру всех родителей
2. Для каждого родителя делаю выборку всех детей:
Код: Выделить всё
SELECT * FROM comments WHERE id= prev.parent_id


Самые большие потери при втором шаге, где рекурсивно делаются вызовы к базе. Я уверен, что эту рекурсию можно сделать на самой базе дабы минимизировать потери времени.

К сожалению, я не очень хорошо разбираюсь с SQL, но активно читаю мануалы и исходники. Ну а заодно, прошу вас, форумчане помочь мне в составлении селекта. Огромное спасибо всем заглянувшим :)
Для получения ответа надо продемонстрировать качества, позволяющие стать компетентным — внимательность, вдумчивость, наблюдательность, желание активно участвовать в выработке решения.

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 16.08.2005 (Вт) 9:14

Поищи нашу с skiperski дискуссию. Вообщем, мы пришли к выводу, что в один запрос такое не сделать. Нужна вспомогательная процедура, которая будет определять и заполнять "глубину" вложенности каждого элемента. Если твоя задача терпит разбиение на два этапа, то мы нашли довольно хорошее решение.
Lasciate ogni speranza, voi ch'entrate.

gaidar
System Debugger
System Debugger
 
Сообщения: 3152
Зарегистрирован: 23.12.2001 (Вс) 13:22

Сообщение gaidar » 16.08.2005 (Вт) 9:47

А вот и нет :). Если использовать SQL Server 2005, то как раз можно обойтись одной процедурой (с использованием Common Table Expression, CTE).

Поле has_childs - лишнее. Этот параметр должен определяться именно по _наличию_ элементов с parent_id, являщимся id этого элемента.

ID | PublicationID | Content | ParentID

Код: Выделить всё
WITH C (ID, PublicationID, Content, ParentID, NestingLevel) AS
(
   SELECT B.ID, B.PublicationID, B.Content, B.ParentID, 1 FROM Comments AS B WHERE ParentID = 0
   UNION ALL
   SELECT B.BrandID, B.[Name], B.ParentID, (NestingLevel + 1) FROM Comments AS B
      INNER JOIN C ON C.ID = B.ParentID
)

SELECT * FROM C
The difficult I’ll do right now. The impossible will take a little while. (c) US engineers in WWII
I don't always know what I'm talking about, but I know I'm right. (c) Muhammad Ali

Konst_One
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
Аватара пользователя
 
Сообщения: 3041
Зарегистрирован: 09.04.2004 (Пт) 13:47
Откуда: Химки

Сообщение Konst_One » 16.08.2005 (Вт) 10:29

а в оракле еще проще через CONNECT BY :wink:

Ennor
Конструктивный критик
Конструктивный критик
 
Сообщения: 2504
Зарегистрирован: 18.12.2001 (Вт) 3:58
Откуда: Калуга -> Москва

Сообщение Ennor » 16.08.2005 (Вт) 11:29

FAKK2: Я так понял, что с конкретным сервером ты еще не определился? Это создаст определенные проблемы.
gaidar, Юкон официально еще не вышел :). Я понимаю, что это вопрос максимум месяца, но тем не менее. Хотя согласен - конструкция красивая. Другой вопрос, насколько она эффективна при выполнении, а то насмотрелся я уже на такую убийственную красоту...

У нас, на MSSQL 2000, я решил проблему получения иерархии через табличную функцию - это такой объект, из которого можно делать селекты, как из таблицы, но который при этом может быть внутри себя весьма сложен по коду (если кто не в курсе). Внутри нее, разумеется, банальный цикл, но при грамотной раскладке индексов работает нормально. Общий смысл таков:
Код: Выделить всё
CREATE FUNCTION dbo.GetBranchSubTree
  (@BranchId int)
RETURNS @Ret TABLE
  (Id int,
  NestLevel int,
  ParentId int NULL,
  Title varchar(200) NULL)
AS

-- (C) 2004 Ennor Tiegael

-- Возвращает список всех филиалов, подчиненных данному, включая и его самого

BEGIN

declare @Nest int

-- Check for empty argument
if @BranchId is null
  set @BranchId = dbo.GetCurrentBranchId()

set @Nest = 0

insert into @Ret
select Id, @Nest, ParentId, Title
from Branches
where Id = @BranchId

-- Recursive call for descendant branches
WHILE (@@ROWCOUNT > 0)
  begin
 
  -- Increment NestLevel
  set @Nest = @Nest + 1
 
  -- Insert next level of tree
  insert into @Ret
  select Id, @Nest, ParentId, Title
  from Branches
  where ParentId in (select Id from @Ret)
    and Id not in (select Id from @Ret)
 
end

-- Done!
RETURN
END

Как видишь, для твоих конкретных требований может потребоваться ну разве что минимальная модификация алгоритма. Да, структура нашей таблицы в общем совпадает с комментариями gaidar'a - он дело говорит, ты его слушай :).

Да, вдогонку к дискуссии: средствами ANSI SQL в один селект - без циклов и привлечения server-specific extentions - эту задачу не решить, проверено :).

FaKk2
El rebelde gurú
El rebelde gurú
Аватара пользователя
 
Сообщения: 2031
Зарегистрирован: 09.03.2003 (Вс) 22:10
Откуда: Los Angeles

Сообщение FaKk2 » 16.08.2005 (Вт) 16:42

Как раз таки сервер конкретен :(

Это MySQL ветки 4.1xx
Для получения ответа надо продемонстрировать качества, позволяющие стать компетентным — внимательность, вдумчивость, наблюдательность, желание активно участвовать в выработке решения.

Ennor
Конструктивный критик
Конструктивный критик
 
Сообщения: 2504
Зарегистрирован: 18.12.2001 (Вт) 3:58
Откуда: Калуга -> Москва

Сообщение Ennor » 16.08.2005 (Вт) 17:37

А почему именно его, если не секрет? Просто, если уж вести речь о бесплатном сыре, то я бы скорее смотрел в сторону PostgreSQL - он получше будет, особенно с точки зрения лицензии...

FaKk2
El rebelde gurú
El rebelde gurú
Аватара пользователя
 
Сообщения: 2031
Зарегистрирован: 09.03.2003 (Вс) 22:10
Откуда: Los Angeles

Сообщение FaKk2 » 16.08.2005 (Вт) 18:36

MySQL, потому что у хостера эта база.
Для получения ответа надо продемонстрировать качества, позволяющие стать компетентным — внимательность, вдумчивость, наблюдательность, желание активно участвовать в выработке решения.

FaKk2
El rebelde gurú
El rebelde gurú
Аватара пользователя
 
Сообщения: 2031
Зарегистрирован: 09.03.2003 (Вс) 22:10
Откуда: Los Angeles

Сообщение FaKk2 » 16.08.2005 (Вт) 18:36

Я пишу на PHP.
Для получения ответа надо продемонстрировать качества, позволяющие стать компетентным — внимательность, вдумчивость, наблюдательность, желание активно участвовать в выработке решения.

gaidar
System Debugger
System Debugger
 
Сообщения: 3152
Зарегистрирован: 23.12.2001 (Вс) 13:22

Сообщение gaidar » 16.08.2005 (Вт) 19:13

Ennor писал(а):gaidar, Юкон официально еще не вышел :). Я понимаю, что это вопрос максимум месяца, но тем не менее. Хотя согласен - конструкция красивая. Другой вопрос, насколько она эффективна при выполнении, а то насмотрелся я уже на такую убийственную красоту...


Производительность даже Выше, чем при использовании временных таблиц и таких циклов. Сам проверял.
The difficult I’ll do right now. The impossible will take a little while. (c) US engineers in WWII
I don't always know what I'm talking about, but I know I'm right. (c) Muhammad Ali

Ennor
Конструктивный критик
Конструктивный критик
 
Сообщения: 2504
Зарегистрирован: 18.12.2001 (Вт) 3:58
Откуда: Калуга -> Москва

Сообщение Ennor » 17.08.2005 (Ср) 0:16

Мускул, значит... Я в нем не силен, признаться, но аналогичный функционал там просто обязан быть. Может даже специальная заточка присутствовать под это дело, он же веб-ориентированный весь из себя. А так - лучше на специализированный форум по нему, хотя бы даже сюда.

FaKk2
El rebelde gurú
El rebelde gurú
Аватара пользователя
 
Сообщения: 2031
Зарегистрирован: 09.03.2003 (Вс) 22:10
Откуда: Los Angeles

Сообщение FaKk2 » 17.08.2005 (Ср) 1:43

На работе я порыл по инету, наткнулся на термин PEAR Nested Set. Поиск в гугле вывел меня на немецкий сайт.

Там же есть демка, походу это то что мне нужно. Дома разберусь.
Для получения ответа надо продемонстрировать качества, позволяющие стать компетентным — внимательность, вдумчивость, наблюдательность, желание активно участвовать в выработке решения.

Inferno
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 179
Зарегистрирован: 26.01.2005 (Ср) 1:06

Сообщение Inferno » 17.08.2005 (Ср) 4:48

Эхх усложняем на ровном месте.
Выкидываем поле child Тип поля Id изменяем на binary
Если у нас родительский узел пишем в поле 1. Если добавляем в родительский узел 1 дочернюю ветвь 1:1 Ну и т.д.
Получаем простой и ненавязчивый SQL
Select from comment where id like 'Our_Value%' Order by id
В итоге получаем нечто
1
1:1
1:2
1:2:1
1:2:1:1
1:2:1:2
Просто и без фанатизма.

FaKk2
El rebelde gurú
El rebelde gurú
Аватара пользователя
 
Сообщения: 2031
Зарегистрирован: 09.03.2003 (Вс) 22:10
Откуда: Los Angeles

Сообщение FaKk2 » 17.08.2005 (Ср) 5:57

Окей, как мне получить указанную в первом посте конструкцию используя твой пример?
Для получения ответа надо продемонстрировать качества, позволяющие стать компетентным — внимательность, вдумчивость, наблюдательность, желание активно участвовать в выработке решения.

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 17.08.2005 (Ср) 7:22

Inferno, не все так просто. Угадай, как будет отсортирован следующий набор?
1:1
1:2
...
1:9
1:10
1:11
?

Или ты предлагаешь в каждой записи делать ведущие нули?
Тоже идея, но сколько их использовать? Если слишком мало, то система будет ограниченной по числу комментариев. Если слишком много, то ключ будет слишком большим и поиск по нему будет долгим.
Lasciate ogni speranza, voi ch'entrate.

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 17.08.2005 (Ср) 7:24

FAKK2 писал(а):На работе я порыл по инету, наткнулся на термин PEAR Nested Set. Поиск в гугле вывел меня на немецкий сайт.

Там же есть демка, походу это то что мне нужно. Дома разберусь.

Да, это именно то, что тебе нужно.
Про Nested Set (вложенные наборы) я видел доку на русском языке, если интересно, постараюсь поискать. Там правда такие простые конструкции, как ID-ParentID почти не рассматриваются, рассматриваются более сложные и гораздо более эффективные.
Lasciate ogni speranza, voi ch'entrate.

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 18.08.2005 (Чт) 21:05

Для простейших случаев предложение от Inferno имеет смысл, но в чуть доработанном виде. Когда-то и сам делал именно такой форум и после перебора вариантов решений остановился именно на этом как на самом простом. Я писал на Access, потому и расчёты сделаны применительно к нему. Основное ограничение - невозможно сохранить бесконечное дерево, но в реальных тредах этого и не нужно. Итак, длина простого строкового поля 255 символов. Я брал по 3 символа на тред, т.е. в теме на одном уровне может быть 999 ответов, а учитывая 0, то все 1000. Даже самая живучая местная тема не дотягивает до этого кол-ва. Соответственно групп может быть 85 (255 / 3), что задаёт глубину ветки. В реальных форумах этого тоже достаточно. Первым полем в индексе было поле ID темы, потом вот это текстовое. И сортировалось правильно, и работало относительно быстро, и не зависило от конкретной БД. При использовании полей других типов, например мемо, можно добиться и "бесконечности". Или при использовании в кодировании номера ответа не только цифр, а и букв, можно увеличить либо кол-во ответов в одном уровне, либо, сократив номер до двух позиций, учеличить глубину.

Inferno
Продвинутый пользователь
Продвинутый пользователь
 
Сообщения: 179
Зарегистрирован: 26.01.2005 (Ср) 1:06

Сообщение Inferno » 19.08.2005 (Пт) 3:06

to Alibek - Сорри был не прав. Надо меньше пить :)

Код: Выделить всё
CREATE TABLE Test (
  ID int(11) NOT NULL auto_increment,
  publication_id text NOT NULL,
  ...
  ...
  ...
  PRIMARY KEY  (ID)
);


Так по идее и с той же структурой построения должно работать

Select * from test where Order by ID, publication_id ASC

Ну естественно поле техт больших вложений не даст, поэтому если не хватает уровня вложенности надо изменить его тип на одну из вариаций блоба

FaKk2
El rebelde gurú
El rebelde gurú
Аватара пользователя
 
Сообщения: 2031
Зарегистрирован: 09.03.2003 (Вс) 22:10
Откуда: Los Angeles

Сообщение FaKk2 » 21.08.2005 (Вс) 8:07

Потратил несколько вечеров на вникание концепции, и внедрению в существующий движок. Результат можно наблюдать на http://kpnemo.ru. На текущий момент я еще не определился с внешним оформлением тредов :(
Для получения ответа надо продемонстрировать качества, позволяющие стать компетентным — внимательность, вдумчивость, наблюдательность, желание активно участвовать в выработке решения.


Вернуться в Базы данных

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex-бот и гости: 1

    TopList