2013-04-17 22 views
0

我有一个应用程序设置了嵌套评论附加到帖子。由于硬盘空间的价格便宜,我决定使用closure table方法(幻灯片40)进行评论,与查询和管理树结构似乎相当容易。但是,我遇到了一个问题。我似乎无法弄清楚如何根据帖子ID抓取树形路径,而不是祖先ID(幻灯片49)。使用JOIN在闭包表上运行SELECT查询?

我的数据库结构如下:

table: comment_paths 
-------------------- 
parent_id (fk on comments.id) 
child_id (fk on comments.id) 
depth 

table: comments 
--------------- 
id 
parent_id (fk on comments.id) 
post_id (fk on posts.id) 
text 

table: posts 
--------------- 
id 
name 

如果我知道PARENT_ID事前,如幻灯片,它是简单的抢树:

SELECT c.*, p.* 
FROM comments AS c 
JOIN comment_paths AS p 
ON c.id = p.child_id 
WHERE p.parent_id = 1 

不过,我不知道事先知道parent_id;我只知道post_id。数据库设置方式,有一个以上的树与帖子相关联:

    [post] 
----------------------------------------- 
[comment]  [comment]  [comment] depth: 0 
    |        | 
[reply]       [reply] depth: 1 
    | | 
[r] [r]         depth: 2 

我最初的解决方案是这样的查询:

SELECT c.*, p.* 
FROM comments AS c 
JOIN comment_paths AS p 
ON c.id = p.child_id 
WHERE p.parent_id IN 
    (SELECT id FROM comments WHERE parent_id IS NULL AND post_id = 6) 

它返回正确的数据,但我感觉像一个嵌套的SELECT,这是不正确的。有一个更好的方法吗?

谢谢!

+0

尝试此查询'选择C *,P * FROM 评论为C JOIN comment_paths为P。 ON c.id = p.parent_id WHERE c.parent_id IS NULL AND c.post_id = 6' – Meherzad

+0

@Meherzad没有工作。 :(只返回了树的顶部 – Patrick

回答

2

我真的不能想到更好的方法。我会做的唯一的变化是使用exists代替:

SELECT c.*, p.* 
FROM comments AS c 
JOIN comment_paths AS p 
ON c.id = p.child_id 
WHERE EXISTS 
(SELECT * FROM comments c2 WHERE p.parent_id = c2.id AND c2.parent_id IS NULL AND c2.post_id = 6) 

我很感兴趣,看看是否有其实是一个更好的方法,虽然。

更新:

我不确定你使用的是什么RDMS。但是,如果递归查询是可用的,我想你可以得到完全从该comments_path表走:

;with cte as(
select c.*, 0 as depth 
from comments c 
where c.post_id = 6 and c.parent_id is null 
union all 
select c.*, cte.depth + 1 
from comments c 
join cte on c.parent_id = cte.id) 

select * from cte 
+0

感谢您的回答。是否有任何理由使用'EXISTS'与'IN'?代替它会返回一个非常不同的数据集。记录在comment_paths集中而不是评论集 – Patrick

+0

不同的结果集是由于连接错误(我有“= p.parent_id”而不是“= p.child_id”)。根据我的经验,EXISTS表现更好在某些情况下,可能没有性能提升,但它应该始终如一,如果不比IN更好。 –

+0

我刚刚看到递归查询更新。这绝对是我想用提供它的RDMS应该比闭包表更快,但是我希望我的项目能够在尽可能多的RDMS上运行,并且避免RDMS特定的查询只是为了将错误降到最低。尽管更新! – Patrick