首页 新闻 会员 周边

关联4张表的SQL查询难题,还要尽可能考虑到性能

0
悬赏园豆:200 [待解决问题]

 

数据库表结构如图,一个文章可以有N个标签,标签和标签之间是树形结构。

问:查询出所有tag.name='互联网' and tag.parentid='互联网'.Id 的 article.title和users.name

不知道这个伪代码有没有表述清楚,就是说不只要查询出标签名称是‘互联网’的所有文章标题和用户名,还要符合‘互联网’的下一级所有标签,比如‘移动互联网’等等。

请教大家这条SQL语句该怎么写,数据库是SQL server。 谢谢!

doasp的主页 doasp | 初学一级 | 园豆:2
提问于:2012-03-31 10:29
< >
分享
所有回答(8)
0

额,没有明白什么是“ 还要符合‘互联网’的下一级所有标签,比如‘移动互联网’等等

辰666 | 园豆:222 (菜鸟二级) | 2012-03-31 10:37

比如'互联网'这个标签的ID是1,那么'移动互联网'的parentid就是1,'互联网'是'移动互联网'的父级。深度最多两级。

换一种说法,查'互联网'这个标签的文章,打了'移动互联网'这个标签的文章也要查出来

支持(0) 反对(0) doasp | 园豆:2 (初学一级) | 2012-03-31 10:39
0

用的什么数据库?Oracle ?SqlServer。
Oracle的话可以使用 start with... connect by prior 实现

webaspx | 园豆:1973 (小虾三级) | 2012-03-31 11:33

很遗憾,是SQL server。

支持(0) 反对(0) doasp | 园豆:2 (初学一级) | 2012-03-31 11:38

@doasp: SQLServer的话也是有办法的。可以使用CTE实现递归查询。
具体我找了个网址给你,自己看下吧。http://database.51cto.com/art/201010/229272.htm

支持(0) 反对(0) webaspx | 园豆:1973 (小虾三级) | 2012-03-31 13:45
0

建议使用视图设计器做,用那个做出来的话,相应的SQL语句也就有了。

轻狂の书生 | 园豆:1042 (小虾三级) | 2012-03-31 11:39

相应的SQL语句全部是使用join连接4张表,性能恐怕很有问题吧? 

支持(0) 反对(0) doasp | 园豆:2 (初学一级) | 2012-03-31 12:54

@doasp: 这个你可以先做出来,再考虑具体的优化问题,至少知道了SQL语句该怎么写,再努力也就有方向了啊!

支持(0) 反对(0) 轻狂の书生 | 园豆:1042 (小虾三级) | 2012-03-31 13:12
-1
select A.ArticleID,A.title,A.[Name],T.TagName from 
Article_Tag as AT inner join
(select a.id as ArticleID,a.title,a.userid ,u.[name] from Article as a left join Users as u on a.UserID =u.Id) as A
on AT.ArticleID=A.ArticleID
inner join
(select id,[name] as TagName from Tag
where [Name]='互联网' or ParentID in (select id from Tag where [Name]='互联网')
) as T on A.TagID=T.id

字段的名称可以斟酌 大概就是这样子 性能我没建表 不知道

我的理解:Article_Tag是个联系表 一对一  所以我用了inner join  文章和标签都要存在
Fishboy | 园豆:244 (菜鸟二级) | 2012-03-31 13:14
1

如果 是sql 2005则使用cte 表达式的递归调用。

就不是一条SQL了,是两条SQL

无邪兮 | 园豆:207 (菜鸟二级) | 2012-03-31 13:53
2
declare @id int;
select @id=Id from tag where name='互联网'
select A.title,A.content,U.Name from article A
Inner Join Users U on A.UserID=U.Id
Inner Join Article_Tag AT on AT.ArticleID=A.Id
inner Join Tag T on AT.TagID=T.Id
where AT.TagID=@id or T.ParentID=@id

要提高性能,Article表应该做几个冗余字段,如加个用户名、加个标签(用符号分割,保存在一个字段)

ailove | 园豆:382 (菜鸟二级) | 2012-03-31 13:57
0

不必废话。看代码,性能可以自己测量。

 1 --题外话,1.Article-Tag的Id 列是多余的,可以使用复合主键;
2 -- 2.表名应该统一使用单数或复数形式
3 --经典的树形结构问题, 更多可以参考Sql反模式(Sql Anit-Pattern)-第3章
4 --如果tag已经是一个闭包表
5 Select Users.Name, Article.Title
6 From Tag inner join Tag Tag2
7 on Tag.ParentId = Tag2.Id and Tag2.Name = '互联网'
8 inner join Article_Tag
9 on Article_Tag.Id = Tag.Id
10 inner join Article
11 on Article.ID = Article.Article_Id
12 inner join Users
13 on Users.UserId = Article.UserId
14 --如果tag不是闭包表
15 --Sql Server2000以上可以使用Table类型变量
16 declare @TagTree Table (Id int, Level int, Primary Key(id))
17 declare @Level int
18 set @Level = 0
19 insert into @TagTree select Id, @Level from Tag where ParentId is null and Name = '互联网'
20 while (@@rowcount > 0)
21 begin
22 set @Level = @Level+1
23 insert into @TagTree
24 select Tag.Id, @Level
25 from Tag inner join @TagTree tree
26 on Tag.ParentId = tree.Id and tree.Level = @Level-1
27 end
28 Select Users.Name, Article.Title
29 From @TagTree tree inner join Article_Tag
30 on Article_Tag.Id = tree.Id
31 inner join Article
32 on Article.ID = Article.Article_Id
33 inner join Users
34 on Users.UserId = Article.UserId
35 ----Sql Server2005以上可以使用Common Table Expression
36 with TagTree (Id)
37 As
38 (
39 Select Id
40 from Tag
41 where ParentId is null and Name = '互联网'
42 union all
43 Select Tag.Id
44 from Tag inner join TagTree
45 on Tag.ParentId = TagTree.Id
46 )
47 Select Users.Name, Article.Title
48 From TagTree inner join Article_Tag
49 on Article_Tag.Id = TagTree.Id
50 inner join Article
51 on Article.ID = Article.Article_Id
52 inner join Users
53 on Users.UserId = Article.UserId
ChatinCode | 园豆:2272 (老鸟四级) | 2012-04-01 12:49
0

cte  递归 是一个解决方法,还有就是 4个表 外加 tags 表相互连接。

性能好不好要看执行计划才知道,join 替换成子查询可能性能会好一点。

Fanr_Zh | 园豆:368 (菜鸟二级) | 2012-11-10 01:50
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册