Несколько левых соединений показывают отчетливый результат с последней датой - PullRequest
3 голосов
/ 22 мая 2019

Я хочу создать доску обсуждений. Поэтому у меня есть 3 таблицы: t_posts, t_boards, t_board_categories. Сообщения содержат темы (где post_post_id IS NULL) и ответы на темы (где post_post_id IS NULL), поэтому он ссылается на себя. Теперь я хочу показать последние 5 сообщений (Темы и / или Ответы) во всех форумах всех категорий. В настоящее время sql выглядит так:

SELECT p.post_id, 
       p.post_board_id, 
       p.post_user_id, 
       p2.post_title, 
       bc.bc_name, 
       Max(p.post_date) post_date 
FROM   t_posts p 
       LEFT JOIN t_posts p2 
              ON ( p2.post_post_id IS NULL 
                   AND ( p2.post_id = p.post_id 
                          OR p.post_post_id = p2.post_id ) ) 
       LEFT JOIN t_boards b 
              ON b.board_id = p.post_board_id 
       LEFT JOIN t_board_categories bc 
              ON bc.bc_id = b.board_bc_id 
WHERE  p.post_system_id = '1' 
       AND p.post_deleted = 0 
       AND bc.bc_deleted = 0 
       AND b.board_deleted = 0 
GROUP  BY p.post_id, 
          p2.post_id 
ORDER  BY p2.post_date DESC 
LIMIT  5 

Результат - почти то, что я хочу, за исключением того, что несколько ответов в одном потоке приведут к отображению только этого одного потока. Мне нужны 5 разных тем с самыми последними ответами, а не только одна 5 раз.

Я присоединяюсь к t_posts p2 для показа оригинального заголовка темы.

Я также пытался добавить DISTINCT p2.post_id в SELECT, но это ничего не меняет.

Схема:

CREATE TABLE `t_board_categories` (
 `bc_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `bc_name` varchar(128) COLLATE utf8_unicode_ci DEFAULT '',
 `bc_prio` int(11) NOT NULL DEFAULT '0',
 `bc_system_id` int(10) unsigned NOT NULL DEFAULT '0',
 `bc_deleted` tinyint(1) NOT NULL DEFAULT '0',
 PRIMARY KEY (`bc_id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

CREATE TABLE `t_boards` (
 `board_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `board_bc_id` int(10) unsigned DEFAULT NULL,
 `board_name` varchar(128) COLLATE utf8_unicode_ci DEFAULT NULL,
 `board_subtitle` text COLLATE utf8_unicode_ci,
 `board_prio` int(11) NOT NULL DEFAULT '0',
 `board_system_id` int(10) unsigned NOT NULL DEFAULT '0',
 `board_deleted` tinyint(4) NOT NULL DEFAULT '0',
 PRIMARY KEY (`board_id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

CREATE TABLE `t_posts` (
 `post_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
 `post_user_id` bigint(20) unsigned DEFAULT NULL,
 `post_title` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
 `post_text` text COLLATE utf8_unicode_ci NOT NULL,
 `post_post_id` bigint(20) unsigned DEFAULT NULL,
 `post_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
 `post_board_id` int(10) unsigned NOT NULL DEFAULT '0',
 `post_system_id` int(10) unsigned NOT NULL DEFAULT '0',
 `post_deleted` int(2) NOT NULL DEFAULT '0',
 PRIMARY KEY (`post_id`)
) ENGINE=InnoDB AUTO_INCREMENT=205 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

INSERT INTO `t_board_categories` (`bc_id`, `bc_name`, `bc_prio`, `bc_system_id`, `bc_deleted`) VALUES (1, 'Test-Category', '1', '1', '0');

INSERT INTO `t_boards` (`board_id`, `board_bc_id`, `board_name`, `board_subtitle`, `board_prio`, `board_system_id`, `board_deleted`) VALUES (1, '1', 'Test-Board', 'Board Subtitle', '1', '1', '0');

INSERT INTO `t_posts` (`post_id`, `post_user_id`, `post_title`, `post_text`, `post_post_id`, `post_date`, `post_board_id`, `post_system_id`, `post_deleted`) VALUES
(1, 14, 'Thread 1', 'Test1', NULL, '2019-05-22 00:18:25', 1, 1, 0),
(2, 14, 'Thread 2', 'Test2', NULL, '2019-05-22 00:18:44', 1, 1, 0),
(3, 14, 'Thread 3', 'Test 3', NULL, '2019-05-22 00:18:51', 1, 1, 0),
(4, 19, 'Thread 4', 'Test 4', NULL, '2019-05-22 00:19:02', 1, 1, 0),
(5, 19, 'Thread 5', 'Test 5', NULL, '2019-05-22 00:19:07', 1, 1, 0),
(6, 19, 'Thread 6', 'Test 6', NULL, '2019-05-22 00:19:15', 1, 1, 0),
(7, 14, 'Reply', 'A', 5, '2019-05-22 00:19:46', 1, 1, 0),
(8, 14, 'Reply', 'B', 5, '2019-05-22 00:19:47', 1, 1, 0),
(9, 14, 'Reply', 'C', 5, '2019-05-22 00:19:49', 1, 1, 0);

Ожидаемый результат: одна строка для потока 1-5 с идентификатором пользователя и датой последнего ответа (идентификатор пользователя: 14, дата: 2019-05-22 00:19:49 для потока 5, для последней даты потока 1-4 это дата потока, ИД пользователя является ИД автора темы)

Я работал над этим весь вечер, было бы здорово получить некоторую помощь. Заранее спасибо!

1 Ответ

1 голос
/ 22 мая 2019

Ваши примерные данные предполагают, что уровни сообщений не могут охватывать более двух уровней (post_post_id не может быть идентификатором сообщения, где post_post_id не равно нулю). Предполагая, что вы можете попытаться использовать коррелированные подзапросы для получения подпостов и поста для поста, упорядочить их по убыванию по дате и использовать LIMIT, чтобы выбрать верхний. Также отсортируйте основной запрос по дате убывания последнего подпоста и используйте LIMIT, чтобы получить топ 5. Что-то вроде:

SELECT bc1.bc_id,
       bc1.bc_name,
       b1.board_id,
       b1.board_name,
       p1.post_id,
       p1.post_title,
       (SELECT p2.post_title
               FROM t_posts p2
               WHERE p1.post_id IN (p2.post_id,
                                    p2.post_post_id) 
               ORDER BY p2.post_date DESC
               LIMIT 1) last_post_title,
       (SELECT p2.post_user_id
               FROM t_posts p2
               WHERE p1.post_id IN (p2.post_id,
                                    p2.post_post_id)
               ORDER BY p2.post_date DESC
               LIMIT 1) last_post_user_id,
       (SELECT p2.post_date
               FROM t_posts p2
               WHERE p1.post_id IN (p2.post_id,
                                    p2.post_post_id) 
               ORDER BY p2.post_date DESC
               LIMIT 1) last_post_date
       FROM t_posts p1
            INNER JOIN t_boards b1
                       ON b1.board_id = p1.post_board_id
            INNER JOIN t_board_categories bc1
                       ON bc1.bc_id = b1.board_bc_id
       WHERE p1.post_post_id IS NULL
       ORDER BY last_post_date DESC
       LIMIT 5;

дб <> скрипка

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...