上一篇简要介绍了图数据库的一些基本内容(初识SQL Server2017 图数据库(一)),本篇经过对比关系型一些语法来体现图数据库模式的一些优势,好比查询方便,语句易理解等。html
在图数据库模型上构建查询的优点:node
T-SQL 带给图表查询一些新的语法。在SELECT语句中咱们有一些特殊的语句来关联点和边。让咱们来演练一些,构建查询语句检索发帖和回复,以下:数据库
FROM dbo.ForumPosts ReplyPost, dbo.ForumPosts RepliedPost
FROM dbo.ForumPosts ReplyPost, dbo.Reply_to, dbo.ForumPosts RepliedPost
FROM dbo.ForumPosts ReplyPost, dbo.Reply_to, dbo.ForumPosts RepliedPost
WHERE MATCH(ReplyPost-(Reply_to)->RepliedPost)
FROM dbo.ForumPosts ReplyPost, dbo.Reply_to, dbo.ForumPosts RepliedPost
WHERE MATCH(ReplyPost-(Reply_to)->RepliedPost)
select RepliedPost.PostId,RepliedPost.PostTitle, ReplyPost.PostId as ReplyId, ReplyPost.PostTitle as ReplyTitle from Forum.ForumPosts ReplyPost, Forum.ForumPosts RepliedPost where ReplyPost.PostId=RepliedPost.ReplyTo
FROM dbo.ForumPosts ReplyPost, dbo.Reply_to, dbo.ForumPosts RepliedPost, dbo.ForumMembers RepliedMember, Written_By RepliedWritten_By
WHERE MATCH(ReplyPost-(Reply_to)->RepliedPost-(RepliedWritten_by)->RepliedMember)
-- Posts 、members 和replies SELECT RepliedPost.PostId,RepliedPost.PostTitle,RepliedMember.MemberName, ReplyPost.PostId as ReplyId, ReplyPost.PostTitle as ReplyTitle FROM dbo.ForumPosts ReplyPost, dbo.Reply_to, dbo.ForumPosts RepliedPost, dbo.ForumMembers RepliedMember, Written_By RepliedWritten_By WHERE MATCH(ReplyPost-(Reply_to)->RepliedPost-(RepliedWritten_by)->RepliedMember)
SELECT RepliedPost.PostId,RepliedPost.PostTitle, ReplyPost.PostId as ReplyId, ReplyPost.PostTitle as ReplyTitle, RepliedMember.MemberName FROM Forum.ForumPosts ReplyPost, Forum.ForumPosts RepliedPost, Forum.ForumMembers RepliedMember WHERE ReplyPost.PostId=RepliedPost.ReplyTo and RepliedPost.OwnerId=RepliedMember.MemberId
From dbo.ForumPosts ReplyPost, dbo.Reply_to, dbo.ForumPosts RepliedPost,
dbo.ForumMembers RepliedMember, Written_By RepliedWritten_By,
dbo.ForumMembers ReplyMember, Written_By ReplyWritten_By
WHERE MATCH(ReplyMember<-(ReplyWritten_By)-ReplyPost-(Reply_to)->RepliedPost-(RepliedWritten_by)->RepliedMember)
-- Posts and members and their replies and members SELECT RepliedPost.PostId, RepliedPost.PostTitle,RepliedMember.MemberName, ReplyPost.PostId as ReplyId, ReplyPost.PostTitle as ReplyTitle, ReplyMember.MemberName [ReplyMemberName] FROM dbo.ForumPosts ReplyPost, dbo.Reply_to, dbo.ForumPosts RepliedPost, dbo.ForumMembers RepliedMember, Written_By RepliedWritten_By, dbo.ForumMembers ReplyMember, Written_By ReplyWritten_By WHERE MATCH(ReplyMember<-(ReplyWritten_By)-ReplyPost-(Reply_to)->RepliedPost-(RepliedWritten_by)->RepliedMember)
SELECT RepliedPost.PostId,RepliedPost.PostTitle, RepliedMember.MemberName, ReplyPost.PostId as ReplyId, ReplyPost.PostTitle as ReplyTitle, ReplyMember.MemberName FROM Forum.ForumPosts ReplyPost, Forum.ForumPosts RepliedPost, Forum.ForumMembers RepliedMember, Forum.ForumMembers ReplyMember WHERE ReplyPost.PostId=RepliedPost.ReplyTo and RepliedPost.OwnerId=RepliedMember.MemberId and ReplyPost.OwnerId=ReplyMember.MemberId
统计每篇帖子的回复数post
SELECT distinct RepliedPost.PostID,RepliedPost.PostTitle, RepliedPost.PostBody, count(ReplyPost.PostID) over(partition by RepliedPost.PostID) as TotalReplies FROM dbo.ForumPosts ReplyPost, Reply_To, dbo.ForumPosts RepliedPost WHERE MATCH(ReplyPost-(Reply_To)->RepliedPost)
在这个语句中咱们统计了每一篇回复的数量,可是仅仅在一个层面中,并非在整个回复的树结构里面。性能
根贴(主贴)的列表url
咱们经过下面不使用MATCH的语句获得全部的根贴:spa
SELECT Post1.PostId,Post1.PostTitle FROM dbo.ForumPosts Post1 WHERE $node_id not in (select $from_id from dbo.Reply_To
MATCH语法只是容许咱们关联三个或者更多的实体(好比两个节点和一个关系)。当咱们只想关联其中两个的时候,只须要一个常规的链接或者子查询。如上面的语句同样。code
在结果中添加‘Level’字段htm
添加一个‘Level’字段,显示树结构。在T-SQL中有一个简单的语法,叫作CTE实现递归。可是有一个问题,不能使用MATCH语法在一个派生表上,此时可使用CTE。若是有必要,能够在CTE中使用MATCH,可是反之就不行了,有这样的限制。下面展现一下使用常规的关系仅仅使用CTE来迭代,代码以下:对象
with root as ( select $node_id as node_id,RootPosts.PostId, RootPosts.PostTitle, 1 as Level, 0 as ReplyTo from dbo.ForumPosts RootPosts where $node_id not in (select $from_id from dbo.reply_to) union all select $node_id,ReplyPost.PostId, ReplyPost.PostTitle, Level+1 as [Level], root.PostId as ReplyTo from dbo.ForumPosts ReplyPost, reply_to, root where ReplyPost.$node_id=reply_to.$from_id and root.node_id=reply_to.$to_id ) select PostId,PostTitle, Level, ReplyTo from root
检索一个帖子中的全部回复
使用CTE递归语法,咱们能够用一种树结构检索一个帖子的全部回复。若是使用常规的语法不能在检索帖子1的时候检索贴子3,由于3是对2的回复,而2是对1的回复。使用CTE.当查询帖子1的全部回复时能检索贴子3。代码以下:
with root as ( select $node_id as node_id,RootPosts.PostId,RootPosts.PostTitle, 1 as Level, 0 as ReplyTo from dbo.ForumPosts RootPosts where PostId=1 union all select $node_id,ReplyPost.PostId, ReplyPost.PostTitle, Level+1 as [Level],root.PostId as ReplyTo from dbo.ForumPosts ReplyPost, reply_to, root where ReplyPost.$node_id=reply_to.$from_id and root.node_id=reply_to.$to_id ) select PostId,PostTitle, Level, ReplyTo from root
咱们也能够反过来作,在树状结构中按顺序检索全部父贴。因为CTE不支持OUTER join,因此要在外部添加,代码以下:
with root as ( select LeafPost.$node_id as node_id,LeafPost.PostId, LeafPost.PostTitle from dbo.ForumPosts LeafPost where LeafPost.PostId=3 -- Single post union all select RepliedPost.$node_id as node_id,RepliedPost.PostId, RepliedPost.PostTitle from dbo.ForumPosts RepliedPost, Reply_to, root where root.node_id=Reply_to.$from_id and Reply_to.$to_id=RepliedPost.$node_id ) select root.PostId,root.PostTitle, RepliedPost.PostId ParentPostId from root left join reply_to on root.node_id=reply_to.$from_id left join dbo.ForumPosts RepliedPost on reply_to.$to_id=RepliedPost.$node_id
检索一个用户全部帖子
查询一个用全部的信息,与帖子不一样,这不须要树,要简单很多:
-- Peter回复的全部帖子 SELECT distinct RepliedPost.PostID,RepliedPost.PostTitle, RepliedPost.PostBody FROM dbo.ForumPosts ReplyPost, Reply_To, dbo.ForumPosts RepliedPost, dbo.ForumMembers Members,Written_By WHERE MATCH(Members<-(Written_By)-ReplyPost-(Reply_To)->RepliedPost) and Members.MemberName='Peter' -- Peter发的全部帖子 SELECT ReplyPost.PostID,ReplyPost.PostTitle,ReplyPost.PostBody, RepliedPost.PostId ReplyTo FROM dbo.ForumPosts ReplyPost, Reply_To, dbo.ForumPosts RepliedPost, dbo.ForumMembers Members,Written_By WHERE MATCH(Members<-(Written_By)-ReplyPost-(Reply_To)->RepliedPost) and Members.MemberName='Peter'
或许你注意到上面两个查询的不一样,就是在展现字段上是否使用DISTINCT。这个去重是由于Peter回复同一个帖子能够超过一次。
在模型中检索Likes(点赞)
这个查询是有意思的:‘Likes’边是成员和发帖表的关系。每个关系都是惟一的,并不受其余关系影响。代码以下:
--点赞的帖子或者被别人点赞的帖子。 SELECT Post.PostID,Post.PostTitle,Member.MemberName FROM dbo.ForumPosts Post, Likes, dbo.ForumMembers Member WHERE MATCH(Member-(Likes)->Post) -- 点赞的人或者被人点赞 SELECT Member.MemberId,Member.MemberName LikeMember, LikedMember.MemberName LikedMemberName FROM dbo.ForumMembers Member, Likes, dbo.ForumMembers LikedMember WHERE MATCH(Member-(Likes)->LikedMember)
还能够很容易地聚合信息,以得到每一个帖子或每一个成员的总的Likes。
--每一个帖子总的likes select Post.PostId,Post.PostTitle, count(*) totalLikes from dbo.ForumPosts Post,Likes, dbo.ForumMembers Members where Match(Members-(Likes)->Post) group by PostId,PostTitle --每一个成员总的点赞数select LikedMembers.MemberId,LikedMembers.MemberName, count(*) totalLikes from dbo.ForumMembers Members,Likes, dbo.ForumMembers LikedMembers where Match(Members-(Likes)->LikedMembers) group by LikedMembers.MemberId, LikedMembers.MemberName
用户点赞而且回复帖子
咱们也能够建立一些更有趣的查询,例如,查找这些点赞并回复的人,以下:
SELECT Member.MemberName,Member.Memberid,
LikedPost.PostId,LikedPost.PostTitle,
ReplyPost.PostTitle ReplyTitle
FROM dbo.ForumPosts LikedPost, Reply_To, dbo.ForumPosts ReplyPost,
Likes, dbo.ForumMembers Member, Written_By
WHERE MATCH(Member-(Likes)->LikedPost<-(Reply_To)-ReplyPost-(Written_By)->Member)
注意,对于‘Member’节点使用了两次在同一个MATCH表达式中。这造成了一种过滤:点赞而且有回复的成员,须要在‘LikedPost’和‘ReplyPost’中都有记录才能够。
那么在关系型模式中代码以下:
select Likes.MemberId,Members.MemberName from Forum.Likes Likes, Forum.ForumPosts Posts, Forum.ForumMembers Members where Likes.MemberId=Posts.OwnerId and Posts.ReplyTo=Likes.PostId and Members.MemberId=Likes.MemberId
看起来这种写法更难理解和读懂。
回帖给多个帖子的成员
SELECT Members.MemberId, Members.MemberName, Count(distinct RepliedPost.PostId) as Total FROM dbo.ForumPosts ReplyPost, Reply_To, dbo.ForumPosts RepliedPost, Written_By,dbo.ForumMembers Members WHERE MATCH(Members<-(Written_By)-ReplyPost-(Reply_To)->RepliedPost) GROUP BY MemberId, Members.MemberName Having Count(RepliedPost.PostId) >1
回帖个一个帖子屡次的成员:
SELECT Members.MemberId, Members.MemberName, RepliedPost.PostId RepliedId,count(*) as TotalReplies FROM dbo.ForumPosts ReplyPost, Reply_To, dbo.ForumPosts RepliedPost, Written_By,dbo.ForumMembers Members WHERE MATCH(Members<-(Written_By)-ReplyPost-(Reply_To)->RepliedPost) GROUP BY MemberId,MemberName,RepliedPost.PostId Having count(*) >1
上述两种语句中惟一的不一样就是展现结果的聚合。
经过上述构建在图数据模式下的查询和关联,对比了常规语句以及在关系模式下的相同查询,不难发现不管是在易读性,逻辑理解上仍是在性能上都有很大提升。固然这只是第一个版本,因此不免有不少问题, 下一篇我讲介绍这个版本存在的一部分问题。