Как сделать заказ по номеру раздела и подраздела в MySQL? - PullRequest
0 голосов
/ 24 февраля 2020

У меня есть такая таблица:

+-----+-------------------------------------+--------------------------+---------------+
| id  | parent_id |  comment_text           | date_posted              |
+-----+-------------------------------------+--------------------------+---------------+
|   1 | 0         |  1                      | 2020-01-08 20:40:00      | 
|   2 | 1         |  1.1                    | 2020-01-08 20:41:00      | 
|   3 | 0         |  2                      | 2020-01-08 20:42:00      | 
|   4 | 0         |  3                      | 2020-01-08 20:43:00      | 
|   5 | 3         |  2.1                    | 2020-01-08 20:44:00      | 
|   6 | 2         |  1.1.1                  | 2020-01-08 20:45:00      |
|   7 | 1         |  1.2                    | 2020-01-08 20:46:00      | 

Как получить заказанные комментарии, подобные этой? (ORDER BY date_posted DESC на каждом уровне комментариев и с использованием одного MySQL запроса, потому что мне нужно разбивать их на страницы с использованием предела и смещения).

comment_text           
    3
    2
       2.1
    1
       1.2
       1.1
          1.1.1

Ответы [ 3 ]

0 голосов
/ 29 февраля 2020

Это не очень эффективно, но это дает то, что вы хотите:

SELECT * 
FROM stuff
ORDER BY SUBSTRING_INDEX(comment_text, '.', 1), 
         SUBSTRING_INDEX(comment_text, '.', 2), 
         comment_text
0 голосов
/ 01 марта 2020

SQL

SELECT * FROM tbl
ORDER BY
CAST(SUBSTRING_INDEX(comment_text, '.', 1) AS UNSIGNED) DESC, -- Up to first dot (if any)
CASE WHEN LOCATE('.', comment_text) = 0 -- No dots
     THEN 4294967295                    -- Place higher when no dots
     WHEN CHAR_LENGTH(comment_text) - CHAR_LENGTH(REPLACE(comment_text, '.', '')) = 1
     THEN CAST(SUBSTRING_INDEX(comment_text, '.', -1) AS UNSIGNED) -- Number after dot
     ELSE CAST(SUBSTRING(SUBSTRING_INDEX(comment_text, '.', -2),   -- Between 2 dots
                         1,
                         LOCATE('.', SUBSTRING_INDEX(comment_text, '.', -2))) AS UNSIGNED)
END DESC,
CASE WHEN CHAR_LENGTH(comment_text) - CHAR_LENGTH(REPLACE(comment_text, '.', '')) < 2
     THEN 4294967295                    -- Place higher when less than 2 dots
     ELSE CAST(SUBSTRING_INDEX(comment_text, '.', -1) AS UNSIGNED) -- After second dot
END DESC,
date_posted DESC;

Онлайн-демо

Rextester demo: https://rextester.com/MPXMV17458 (Включает пример в вопросе + еще один пример с некоторыми повторными значениями и целые числа больше 10).

Пояснение

В запросе предполагается, что может быть максимум две точки. Есть три ORDER BY части (кроме окончательного порядка date_posted), представляющие три возможных целых числа в x.y.z. Для первых двух частей, если нет ничего выше, выбирается максимально возможное целое число без знака - так что x будет выше, чем x.y, а x.y будет выше, чем x.y.z (или наоборот, так как порядок нисходящий). Приведение к целым числам без знака гарантирует, что порядок будет работать за пределами 9, поскольку в алфавитном порядке 10 будет располагаться между 1 и 2.

0 голосов
/ 24 февраля 2020

Поскольку вам нужны все комментарии, а не только некоторые, я бы не стал беспокоиться о MySQL части этого, которая будет просто SELECT * FROM Table ORDER BY Table.date_posted DESC. Вы также можете использовать WHERE, но, исходя из вашего примера, вам понадобятся все комментарии.

Полностью рабочий пример здесь: IDEOne Demo

Полностью вывод рабочего примера:

3
2
    2.1
1
    1.2
    1.1
        1.1.1

В PHP просто создайте ха sh, где мы храним комментарии так: parent_id => $commentobj ...

<?php

    $comment_hash = [];

    foreach($comments as $comment) {
        if(!$comment_hash[$comment['parent_id']]) {
            $comment_hash[$comment['parent_id']] = [];
        }

        $comment_hash[$comment['parent_id']][] = $comment;
    }

?>

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

Наша функция рекурсивного отображения.

<?php

    function displayComments($comments, $comment_hash, $depth) {
        foreach($comments as $comment) {
            print(str_repeat(' ', 4 * $depth));
            print($comment['comment_text']);
            print("\n");

            displayComments($comment_hash[$comment['id']], $comment_hash, $depth + 1);
        }
    }

?>

Запуск функции рекурсивного отображения на верхнем уровне (то есть, parentid = 0) комментарии ...

<?php

    displayComments($comment_hash[0], $comment_hash, 0);

?>
...