SQLServer图数据库一些优点
上一篇简要介绍了图数据库的一些基本内容(初识SQL Server2017 图数据库(一)),本篇通过对比关系型一些语法来体现图数据库模式的一些优点,比如查询方便,语句易理解等。
在图数据库模型上构建查询的优势:
T-SQL 带给图表查询一些新的语法。在SELECT语句中我们有一些特殊的语句来关联点和边。让我们来演练一些,构建查询语句检索发帖和回复,如下:
FROM dbo.ForumPosts ReplyPost, dbo.ForumPosts RepliedPost
FROM dbo.ForumPosts ReplyPost, dbo.Reply_to, dbo.ForumPosts RepliedPost
统计每篇帖子的回复数
SELECT distinct RepliedPost.PostID,RepliedPost.PostTitle,RepliedPost.PostBody,count(ReplyPost.PostID) over(partition by RepliedPost.PostID)as TotalRepliesFROM dbo.ForumPosts ReplyPost, Reply_To, dbo.ForumPosts RepliedPostWHERE MATCH(ReplyPost-(Reply_To)->RepliedPost)
在这个语句中我们统计了每一篇回复的数量,但是仅仅在一个层面中,并不是在整个回复的树结构里面。
根贴(主贴)的列表
我们通过下面不使用MATCH的语句得到所有的根贴:
SELECT Post1.PostId,Post1.PostTitleFROM dbo.ForumPosts Post1WHERE $node_id not in (select $from_id from dbo.Reply_To
MATCH语法只是允许我们关联三个或者更多的实体(比如两个节点和一个关系)。当我们只想关联其中两个的时候,只需要一个常规的连接或者子查询。如上面的语句一样。
在结果中添加‘Level’字段
添加一个‘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 ReplyTofrom dbo.ForumPosts RootPostswhere $node_id not in (select $from_id from dbo.reply_to)union allselect $node_id,ReplyPost.PostId, ReplyPost.PostTitle,Level+1 as [Level], root.PostId as ReplyTofrom dbo.ForumPosts ReplyPost, reply_to, rootwhere ReplyPost.$node_id=reply_to.$from_idand root.node_id=reply_to.$to_id)select PostId,PostTitle, Level, ReplyTofrom 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 ReplyTofrom dbo.ForumPosts RootPostswhere PostId=1 union allselect $node_id,ReplyPost.PostId, ReplyPost.PostTitle,Level+1 as [Level],root.PostId as ReplyTofrom dbo.ForumPosts ReplyPost, reply_to, rootwhere ReplyPost.$node_id=reply_to.$from_idand root.node_id=reply_to.$to_id)select PostId,PostTitle, Level, ReplyTofrom root
我们也可以反过来做,在树状结构中按顺序检索所有父贴。由于CTE不支持OUTER join,所以要在外部添加,代码如下:
with root as( select LeafPost.$node_id as node_id,LeafPost.PostId,LeafPost.PostTitlefrom dbo.ForumPosts LeafPostwhere LeafPost.PostId=3 -- Single postunion allselect RepliedPost.$node_id as node_id,RepliedPost.PostId,RepliedPost.PostTitlefrom dbo.ForumPosts RepliedPost, Reply_to, rootwhere root.node_id=Reply_to.$from_idand Reply_to.$to_id=RepliedPost.$node_id)select root.PostId,root.PostTitle,RepliedPost.PostId ParentPostIdfrom rootleft join reply_toon root.node_id=reply_to.$from_idleft join dbo.ForumPosts RepliedPoston reply_to.$to_id=RepliedPost.$node_id检索一个用户所有帖子
查询一个用所有的信息,与帖子不同,这不需要树,要简单不少:
-- Peter回复的所有帖子SELECT distinct RepliedPost.PostID,RepliedPost.PostTitle,RepliedPost.PostBodyFROM dbo.ForumPosts ReplyPost, Reply_To, dbo.ForumPosts RepliedPost,dbo.ForumMembers Members,Written_ByWHERE MATCH(Members<-(Written_By)-ReplyPost-(Reply_To)->RepliedPost)and Members.MemberName='Peter'-- Peter发的所有帖子SELECT ReplyPost.PostID,ReplyPost.PostTitle,ReplyPost.PostBody,RepliedPost.PostId ReplyToFROM dbo.ForumPosts ReplyPost, Reply_To, dbo.ForumPosts RepliedPost,dbo.ForumMembers Members,Written_ByWHERE MATCH(Members<-(Written_By)-ReplyPost-(Reply_To)->RepliedPost)and Members.MemberName='Peter'
或许你注意到上面两个查询的不同,就是在展示字段上是否使用DISTINCT。这个去重是因为Peter回复同一个帖子可以超过一次。
在模型中检索Likes(点赞)
这个查询是有意思的:‘Likes’边是成员和发帖表的关系。每一个关系都是唯一的,并不受其他关系影响。代码如下:
--点赞的帖子或者被别人点赞的帖子。SELECT Post.PostID,Post.PostTitle,Member.MemberNameFROM dbo.ForumPosts Post, Likes,dbo.ForumMembers MemberWHERE MATCH(Member-(Likes)->Post)-- 点赞的人或者被人点赞SELECT Member.MemberId,Member.MemberName LikeMember,LikedMember.MemberName LikedMemberNameFROM dbo.ForumMembers Member, Likes, dbo.ForumMembers LikedMemberWHERE MATCH(Member-(Likes)->LikedMember)
还可以很容易地聚合信息,以获得每个帖子或每个成员的总的Likes。
--每个帖子总的likesselect Post.PostId,Post.PostTitle,count(*) totalLikesfrom dbo.ForumPosts Post,Likes,dbo.ForumMembers Memberswhere Match(Members-(Likes)->Post)group by PostId,PostTitle--每个成员总的点赞数select LikedMembers.MemberId,LikedMembers.MemberName,count(*) totalLikesfrom dbo.ForumMembers Members,Likes,dbo.ForumMembers LikedMemberswhere Match(Members-(Likes)->LikedMembers)group by LikedMembers.MemberId,LikedMembers.MemberName
用户点赞并且回复帖子
我们也可以创建一些更有趣的查询,例如,查找这些点赞并回复的人,如下:
SELECT Member.MemberName,Member.Memberid,LikedPost.PostId,LikedPost.PostTitle,ReplyPost.PostTitle ReplyTitleFROM dbo.ForumPosts LikedPost, Reply_To, dbo.ForumPosts ReplyPost,Likes, dbo.ForumMembers Member, Written_ByWHERE MATCH(Member-(Likes)->LikedPost<-(Reply_To)-ReplyPost-(Written_By)->Member)
注意,对于‘Member’节点使用了两次在同一个MATCH表达式中。这形成了一种过滤:点赞并且有回复的成员,需要在‘LikedPost’和‘ReplyPost’中都有记录才可以。
那么在关系型模式中代码如下:
select Likes.MemberId,Members.MemberNamefrom Forum.Likes Likes, Forum.ForumPosts Posts,Forum.ForumMembers Memberswhere Likes.MemberId=Posts.OwnerIdand Posts.ReplyTo=Likes.PostIdand Members.MemberId=Likes.MemberId
看起来这种写法更难理解和读懂。
回帖给多个帖子的成员
SELECT Members.MemberId, Members.MemberName,Count(distinct RepliedPost.PostId) as TotalFROM dbo.ForumPosts ReplyPost, Reply_To, dbo.ForumPosts RepliedPost,Written_By,dbo.ForumMembers MembersWHERE MATCH(Members<-(Written_By)-ReplyPost-(Reply_To)->RepliedPost)GROUP BY MemberId, Members.MemberNameHaving Count(RepliedPost.PostId) >1
回帖个一个帖子多次的成员:
SELECT Members.MemberId, Members.MemberName,RepliedPost.PostId RepliedId,count(*) as TotalRepliesFROM dbo.ForumPosts ReplyPost, Reply_To, dbo.ForumPosts RepliedPost,Written_By,dbo.ForumMembers MembersWHERE MATCH(Members<-(Written_By)-ReplyPost-(Reply_To)->RepliedPost)GROUP BY MemberId,MemberName,RepliedPost.PostIdHaving count(*) >1
上述两种语句中唯一的不同就是展示结果的聚合。
总结
通过上述构建在图数据模式下的查询和关联,对比了常规语句以及在关系模式下的相同查询,不难发现无论是在易读性,逻辑理解上还是在性能上都有很大提高。当然这只是第一个版本,所以难免有很多问题, 下一篇我讲介绍这个版本存在的一部分问题。
posted on 2018-01-25 08:41 NET未来之路 阅读(...) 评论(...) 编辑 收藏转载于:https://www.cnblogs.com/lonelyxmas/p/8349445.html
总结
以上是生活随笔为你收集整理的SQLServer图数据库一些优点的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: Java数字签名——RSA算法
- 下一篇: 关于mysql启动问题---mysqld