我正在研究无限级别的评论-答复系统。并且成功获取父子相对数据行,但是我在订购该行时遇到了麻烦。
这用于创建结果:https://stackoverflow.com/a/5291159/4894502
我得到这样的结果;
comment_id comment parent_id depth rel_path rating
38 Com 1 0 0 0 0
39 Com 2 0 0 0 10
40 Com 3 0 0 0 0
41 Com 1-1 38 1 0/38 0
42 Com 2-1 39 1 0/39 0
44 Com 2-2 39 1 0/39 2
46 Com 3-1 40 1 0/40 0
43 Com 2-1-1 42 2 0/39/42 0
47 Com 2-2-1 44 2 0/39/44 0
45 Com 2-1-1-1 43 3 0/39/42/43 0
但是排序是有问题的,期望的排序是每个子项必须在其父项之下,而子项必须根据某个参数在其中进行排序,例如rating
。如此理想的结果;
comment_id comment parent_id depth rel_path rating
38 Com 1 0 0 0 0
41 Com 1-1 38 1 0/38 0
39 Com 2 0 0 0 10
42 Com 2-1 39 1 0/39 0
43 Com 2-1-1 42 2 0/39/42 0
45 Com 2-1-1-1 43 3 0/39/42/43 0
44 Com 2-2 39 1 0/39 2
47 Com 2-2-1 44 2 0/39/44 0
40 Com 3 0 0 0 0
46 Com 3-1 40 1 0/40 0
或者这样(+按评分顺序)
comment_id comment parent_id depth rel_path rating
39 Com 2 0 0 0 10
44 Com 2-2 39 1 0/39 2
47 Com 2-2-1 44 2 0/39/44 0
42 Com 2-1 39 1 0/39 0
43 Com 2-1-1 42 2 0/39/42 0
45 Com 2-1-1-1 43 3 0/39/42/43 0
38 Com 1 0 0 0 0
41 Com 1-1 38 1 0/38 0
40 Com 3 0 0 0 0
46 Com 3-1 40 1 0/40 0
Db小提琴上的示例 https://www.db-fiddle.com/f/uk3ZDLdD8N5tvhzb9S6rXC/1
示例表:
CREATE TABLE `comment` (
`comment_id` int(11) NOT NULL,
`parent_id` int(11) NOT NULL DEFAULT '0',
`depth` int(4) NOT NULL DEFAULT '0',
`comment` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`rating` int(4) NOT NULL DEFAULT '0'
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
INSERT INTO `comment` (`comment_id`, `parent_id`, `depth`, `comment`, `rating`) VALUES
(42,39, 1,'Com 2-1', 0),
(41,38, 1,'Com 1-1', 0),
(40,0, 0,'Com 3', 0),
(39,0, 0,'Com 2', 20),
(38,0, 0,'Com 1', 0),
(43,42, 2,'Com 2-1-1', 0),
(44,39, 1,'Com 2-2', 2),
(45,43, 3,'Com 2-1-1-1', 0),
(46,40, 1,'Com 3-1', 0),
(47,44, 2,'Com 2-2-1', 0);
ALTER TABLE `comment`
ADD PRIMARY KEY (`comment_id`),
ADD UNIQUE KEY `comment_id` (`comment_id`);
ALTER TABLE `comment`
MODIFY `comment_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=48;
程序(与上面链接中的答案几乎相同):
delimiter #
create procedure comment_hier
(
in param_parent_id smallint unsigned
)
BEGIN
DECLARE v_done TINYINT unsigned default 0;
DECLARE v_depth SMALLINT unsigned default 0;
CREATE TEMPORARY TABLE hier(
comment_id int(11) unsigned,
parent_id int(11) unsigned,
depth int(99) unsigned default 0,
relation_path varchar(360) default 0
)engine = memory;
INSERT INTO hier SELECT comment_id, parent_id, v_depth, 0 FROM comment a WHERE a.parent_id = param_parent_id;
CREATE TEMPORARY TABLE tmp engine=memory SELECT * FROM hier;
while not v_done do
if exists( select 1 from hier h inner join comment a on h.comment_id = a.parent_id and h.depth = v_depth) then
insert into hier
select a.comment_id, a.parent_id, v_depth + 1, CONCAT_WS('/', relation_path, a.parent_id) from comment a
inner join tmp t on a.parent_id = t.comment_id and t.depth = v_depth;
set v_depth = v_depth + 1;
truncate table tmp;
insert into tmp select * from hier where depth = v_depth;
else
set v_done = 1;
end if;
end while;
select
a.comment_id,
a.comment as comment,
a.parent_id as parent_id,
h.depth,
h.relation_path,
a.rating as rating
from
hier h
left join comment a on h.comment_id = a.comment_id
ORDER BY h.depth, a.comment_id;
DROP TEMPORARY TABLE if exists hier;
DROP TEMPORARY TABLE if exists tmp;
END #
运行:
delimiter ;
call comment_hier(0);
我已经工作了几个小时,但无法解决。谢谢。
答案 0 :(得分:3)
要实现不同的排序(仅按顶级注释的等级,仅按层次结构),您需要将所有排序条件添加到hier
表中作为新的层次结构路径。我对您的分层排序路径进行了重组,以同时包含路径和最终注释ID,以便每个初始注释都没有0
而是39
(或38
或40
)作为其第一部分。这使得层次排序变得微不足道。
要按等级排序,必须构造rating/comment_id
的每个路径元素。这使得按顺序(按线程中的相对等级)然后按comment_id
进行排序变得很简单。
结果代码为
模式(MySQL v5.7)
CREATE TABLE `comment` (
`comment_id` int(11) NOT NULL,
`parent_id` int(11) NOT NULL DEFAULT '0',
`depth` int(4) NOT NULL DEFAULT '0',
`comment` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`rating` int(4) NOT NULL DEFAULT '0'
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
INSERT INTO `comment` (`comment_id`, `parent_id`, `depth`, `comment`, `rating`) VALUES
(42,39, 1,'Com 2-1', 0),
(41,38, 1,'Com 1-1', 0),
(40,0, 0,'Com 3', 0),
(39,0, 0,'Com 2', 20),
(38,0, 0,'Com 1', 0),
(43,42, 2,'Com 2-1-1', 0),
(44,39, 1,'Com 2-2', 2),
(45,43, 3,'Com 2-1-1-1', 0),
(46,40, 1,'Com 3-1', 0),
(47,44, 2,'Com 2-2-1', 0);
ALTER TABLE `comment`
ADD PRIMARY KEY (`comment_id`),
ADD UNIQUE KEY `comment_id` (`comment_id`);
ALTER TABLE `comment`
MODIFY `comment_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=48;
#CREATING PROCEDURE
#---------------------------------------------------------------------#
drop procedure if exists comment_hier;
delimiter $$
create procedure comment_hier
(
in param_parent_id smallint unsigned
)
BEGIN
DECLARE v_done TINYINT unsigned default 0;
DECLARE v_depth SMALLINT unsigned default 0;
CREATE TEMPORARY TABLE hier(
comment_id int(11) unsigned,
root_id int(11) unsigned,
parent_id int(11) unsigned,
depth int(99) unsigned default 0,
relation_path varchar(360) default 0,
relation_rating_path varchar(360) default 0
)engine = memory;
INSERT INTO hier SELECT comment_id, comment_id as root_id, parent_id, v_depth, comment_id, concat_ws('/', a.rating, comment_id) FROM comment a WHERE a.parent_id = param_parent_id;
CREATE TEMPORARY TABLE tmp engine=memory SELECT * FROM hier;
while not v_done do
if exists( select 1 from hier h inner join comment a on h.comment_id = a.parent_id and h.depth = v_depth) then
insert into hier
select a.comment_id, t.root_id, a.parent_id, v_depth + 1, CONCAT_WS('/', relation_path, a.comment_id), CONCAT_WS('/', relation_rating_path, a.rating, a.comment_id) from comment a
inner join tmp t on a.parent_id = t.comment_id and t.depth = v_depth;
set v_depth = v_depth + 1;
truncate table tmp;
insert into tmp select * from hier where depth = v_depth;
else
set v_done = 1;
end if;
end while;
#SELECT STATEMENT
#----------------------------------------------------------------------------------#
select
a.comment_id,
a.comment as comment,
a.parent_id as parent_id,
h.depth,
h.relation_path
, h.relation_rating_path
, a.rating as rating
, h.root_id
from
hier h
left join comment a on h.comment_id = a.comment_id
-- for tree-like ordering
-- order by relation_path
-- for rating ordering of the comment
order by relation_rating_path desc, comment_id
;
DROP TEMPORARY TABLE if exists hier;
DROP TEMPORARY TABLE if exists tmp;
END $$
delimiter ;
查询#1
call comment_hier(0);
| comment_id | comment | parent_id | rating | depth | relation_path | relation_rating_path | root_id |
| ---------- | ----------- | --------- | ------ | ----- | ------------- | -------------------- | ------- |
| 47 | Com 2-2-1 | 44 | 0 | 2 | 39/44/47 | 20/39/2/44/0/47 | 39 |
| 44 | Com 2-2 | 39 | 2 | 1 | 39/44 | 20/39/2/44 | 39 |
| 45 | Com 2-1-1-1 | 43 | 0 | 3 | 39/42/43/45 | 20/39/0/42/0/43/0/45 | 39 |
| 43 | Com 2-1-1 | 42 | 0 | 2 | 39/42/43 | 20/39/0/42/0/43 | 39 |
| 42 | Com 2-1 | 39 | 0 | 1 | 39/42 | 20/39/0/42 | 39 |
| 39 | Com 2 | 0 | 20 | 0 | 39 | 20/39 | 39 |
| 46 | Com 3-1 | 40 | 0 | 1 | 40/46 | 0/40/0/46 | 40 |
| 40 | Com 3 | 0 | 0 | 0 | 40 | 0/40 | 40 |
| 41 | Com 1-1 | 38 | 0 | 1 | 38/41 | 0/38/0/41 | 38 |
| 38 | Com 1 | 0 | 0 | 0 | 38 | 0/38 | 38 |