数据库表结构如图,一个文章可以有N个标签,标签和标签之间是树形结构。
问:查询出所有tag.name='互联网' and tag.parentid='互联网'.Id 的 article.title和users.name
不知道这个伪代码有没有表述清楚,就是说不只要查询出标签名称是‘互联网’的所有文章标题和用户名,还要符合‘互联网’的下一级所有标签,比如‘移动互联网’等等。
请教大家这条SQL语句该怎么写,数据库是SQL server。 谢谢!
额,没有明白什么是“ 还要符合‘互联网’的下一级所有标签,比如‘移动互联网’等等 ”
比如'互联网'这个标签的ID是1,那么'移动互联网'的parentid就是1,'互联网'是'移动互联网'的父级。深度最多两级。
换一种说法,查'互联网'这个标签的文章,打了'移动互联网'这个标签的文章也要查出来
用的什么数据库?Oracle ?SqlServer。
Oracle的话可以使用 start with... connect by prior 实现
很遗憾,是SQL server。
@doasp: SQLServer的话也是有办法的。可以使用CTE实现递归查询。
具体我找了个网址给你,自己看下吧。http://database.51cto.com/art/201010/229272.htm
建议使用视图设计器做,用那个做出来的话,相应的SQL语句也就有了。
相应的SQL语句全部是使用join连接4张表,性能恐怕很有问题吧?
@doasp: 这个你可以先做出来,再考虑具体的优化问题,至少知道了SQL语句该怎么写,再努力也就有方向了啊!
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 文章和标签都要存在
如果 是sql 2005则使用cte 表达式的递归调用。
就不是一条SQL了,是两条SQL
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表应该做几个冗余字段,如加个用户名、加个标签(用符号分割,保存在一个字段)
不必废话。看代码,性能可以自己测量。
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
cte 递归 是一个解决方法,还有就是 4个表 外加 tags 表相互连接。
性能好不好要看执行计划才知道,join 替换成子查询可能性能会好一点。