Возможно ли условное ограничение в запросе mySQL? - PullRequest
3 голосов
/ 01 декабря 2009

Я столкнулся с решением относительно обработки многопоточных комментариев в нашем проекте ... У меня есть простая таблица MySQL, которая содержит все комментарии. Есть два типа: родители и дети. Childs представляет ответ родителю или другому ребенку.

Моя проблема:

-Комментарий (глубина 0)
- Ответить Ребенок (глубина 1)
--- Ответ предыдущему ребенку (глубина 2)
-Комментарий (глубина 0)

Представьте вышеприведенную структуру и запрос MySQL с LIMIT 2. Это обрезает последний ответ (глубина 2) На самом деле я хотел бы сказать что-то вроде: попробуйте ограничить до 2, если ребенок оставил до следующего родителя. Пробовал несколько запросов без удачи ...

То, что у меня сейчас есть, выглядит следующим образом:
ВЫБРАТЬ SQL_CALC_FOUND_ROWS * ОТ Комментарии ГДЕ comment_post_id = '{$ _REQUEST ["ID"]}' СОРТИРОВАТЬ ПО comment_id, comment_date DESC LIMIT 10 "

Важные поля таблицы:
comment_id (индекс) | comment_parent_id (содержит comment_id родителя или NULL) | комментарий_дата

Буду очень благодарен за любые идеи !!!

Saludos, Booosh

Ответы [ 4 ]

1 голос
/ 04 февраля 2013

Я столкнулся с той же проблемой, только я шел только на одну глубину.

--Comment (depth: 0)
---Reply  (depth: 1)

Мне удалось использовать один запрос для выбора всех этих записей, при этом ограничение верхнего уровня Comment записей только 10.

SELECT c.* FROM comments AS c WHERE c.OwnerId = 1 AND c.ParentId = 0 LIMIT 10
UNION
SELECT cc.* FROM comments AS cc
    INNER JOIN
    (
        SELECT CommentId FROM comments WHERE OwnerId = 1 AND ParentId = 0 LIMIT 10
    )
    AS c2
    ON cc.ParentId = c2.CommentId

Этот запрос в основном выполняет следующие действия:

  • Получает первые 10 записей, которые являются комментариями верхнего уровня и имеют идентификатор конкретного владельца.
  • Получает все комментарии, у которых родительский идентификатор равен идентификатору комментария, который был возвращен первым запросом и объединяет их в набор результатов.

Хотя я думаю, что этот запрос был бы более эффективным, чем многократные обращения к базе данных для каждой записи, у него все еще есть недостаток: он выполняет первый запрос дважды. Один раз перед объединением и один в объединении.

Кажется, это довольно быстро, но не так быстро, как хотелось бы. Однако, если ваша база данных удаленная и задержка является проблемой, это решение может помочь вам лучше, чем делать несколько удаленных запросов к базе данных.

1 голос
/ 01 декабря 2009

Всегда думайте о вопросе, который вы действительно хотите задать базе данных, и , а затем переводите его в SQL - в этом случае вам нужен «список всех комментариев верхнего уровня с их непосредственными потомками, если таковые имеются» .

например. (Упрощенный)

SELECT * FROM comments c1
LEFT JOIN comments c2 ON c2.parent_comment_id=c1.comment_id
WHERE c1.parent_comment_id IS NULL
ORDER BY c1.comment_date, c1.comment_id, c2.comment_date, c2.comment_id;

С этим результатом вы можете записать их в правильном порядке - если c2.comment_id имеет значение null, это комментарий верхнего уровня без дочерних элементов, а если c1.comment_id повторяется, это еще один дочерний элемент того же комментария.

1 голос
/ 01 декабря 2009

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

например. (Псевдо-код)

findNodes(String parentId, int maxLevel)
{
  select * from posts where parent = parentId
  foreach (result...)
  {
    if (maxLevel > 0) 
    {
      findNodes(result.nodeId, maxLevel - 1)
    }
    doSomethingWIthAResult
  }
}

Чтобы сделать это более кратким способом, есть ряд методов, каждый из которых включает в себя своего рода поле индекса, которое содержит путь к текущей записи. Путь может выглядеть примерно так: TopNode: Child1: Child2: Child3 ... В котором вы можете сделать подобный выбор Выберите * из сообщений, где путь, как "TopNode%" и глубина = 2.

0 голосов
/ 02 декабря 2009

Мне наконец удалось на основании подсказки Грега Адамскиса ... Так что не голосуйте за мой ответ, но проверьте его !!!

Чтобы кратко описать проблему ... Нам нужна нумерация страниц для списка комментариев на нашем сайте. Использование стандартного ограничения может привести к тому, что некоторые комментарии никогда не будут отображаться ... Нам нужен был предел, который затрагивал только наши родительские узлы, а не узлы cild, которые являются ответами ... Длинная история ... однако, возможно, один раз это полезно для кого-то:

    function getComments($comment_parent_id, $scope,&$comments, $db)
    {
        $res = $db->select("SELECT * FROM comments WHERE comment_post_id = '{$_REQUEST["ID"]}' AND comment_parent_id = '{$comment_parent_id}' ORDER BY comment_date DESC LIMIT {$scope}");

        while ($row = mysql_fetch_array($res, MYSQL_ASSOC)) 
        {
            $i = count($comments)+1;

            foreach ($row as $k => $v) {
                $comments[$i][$k] = $v;
            }

            //LOOK FOR REPLIES (childs of parent)
            if (mysql_num_rows($db->select("SELECT * FROM comments WHERE comment_parent_id = '{$row['comment_id']}' LIMIT 1")) != 0 ){
                getComments($row['comment_id'],100,$comments,$db);
            }
        }
    }

    //ARGUMENTS: parent_id (always starting with zero), scope, array holding comments, db class
    getComments(0,5,$comments,$db);
...