多个左联接显示了最后一个日期的不同结果

时间:2019-05-21 22:02:33

标签: mysql sql

我想建立一个讨论区。因此,我有3个表:t_posts,t_boards,t_board_categories。帖子包含线程(其中post_post_id为NULL)并回复线程(其中post_post_id为非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的一行,带有用户ID和最后答复的日期(线程5的用户ID:14,日期:2019-05-22 00:19:49,线程1-4的最后日期是线程日期,用户ID是线程作者用户ID)

我整个晚上都在工作,很高兴能得到一些帮助。预先谢谢你!

1 个答案:

答案 0 :(得分:1)

您的样本数据表明,帖子级别不能超过两个级别(post_post_id不能是post_post_id不为空的帖子的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;

db<>fiddle