赞助商
在实际应用中,我们经常需要用到树型结构功能,数据库结构一般如下

附件: table.jpg

即用一个ParentID来标识该节点从属关系。为了最终生成一棵树,一般做法是把记录选出来,然后在程序里递归重新排好序后再呈现出来,但是如果有大量数据,就带来了性能开销问题。那么能不能直接在数据库利用SQL语句排好树后再输出呢?

SQL2005 有个递归查询功能也就是WITH .. AS 语句。对上面这样的表格使用递归查询,可以查询得到某树支下(包括根)的所有节点记录。类似语句如下:
  1. with RelClass
  2. as
  3. (
  4. select * from CMS_Site_Class where ClassID = 1
  5. union all
  6. select csc.* from CMS_Site_Class as csc inner join RelClass as rc on csc.ClassID_Parent = rc.ClassID )
  7. SELECT * from RelClass
复制代码
将得到ClassID为1的根节点下的所有记录:

附件: r.jpg

但是这个记录集显然没有经过树排序,这时还需要程序里进一步处理才能输出到客户端。在这里我介绍一种WITH 结合 Row_Number() 实现SQL端排序的方法。

先来看看最终的代码:
  1. -- =============================================
  2. -- Author:    <kingimg>
  3. -- Create date: <2009-2-5>
  4. -- Description:    <将指定Int数据左填0到指定宽度>
  5. -- =============================================
  6. CREATE FUNCTION dbo.Lpad
  7. (
  8. @i int,@len int
  9. )
  10. RETURNS nvarchar(max)
  11. AS
  12. BEGIN
  13. RETURN cast (replicate('0', @len - len(@i) ) + convert(nvarchar,@i) as nvarchar(max))
  14. END



  15. -- =============================================
  16. -- Author:    <kingimg>
  17. -- Create date: <2009-2-5>
  18. -- Description:    <生成已排序的树>
  19. -- =============================================
  20. Create PROCEDURE [dbo].[pCMS_Site_Class__GetList]
  21. @ClassID int
  22. AS
  23. BEGIN
  24. with RelClass
  25. as
  26. (
  27. select *,0 as Level,cast('0' as nvarchar(max)) as treepath from CMS_Site_Class where ClassID = @ClassID
  28. union all
  29. select csc.*,rc.[Level] + 1,rc.treepath + dbo.Lpad(Row_Number() over (order by csc.OrderID desc),8) as treepath from CMS_Site_Class as csc inner join RelClass as rc on csc.ClassID_Parent = rc.ClassID )
  30. SELECT * from RelClass order by treepath
  31. END
复制代码
执行以上存储过程,最后就输出结果:

附件: sortedtree.jpg

这棵树已经从上到下按树结构排好序了!程序里只要原样输出即可!

Lpad函数将指定Int型数据左填0,按指定位数输出。关于为什么要用nvarchar(max)的问题,因为其它固定长度时,在递归查询里的rc.treepath + dbo.Lpad(..)时会改变长度,导致查询错误,使用max长度就避免了这个问题。当然,你也可以用固定长度,相加后再convert回来。

好了,这样子我们就实现了完全SQL端生成已排序的树的目的了,完全脱离了程序处理,这个方法看起来效率还不错呢~

我在此抛砖引玉了,各位如果有可以改进的地方,请贴出来~


文/被诅咒的天才  出处/博客园
赞助商
赞助商
TOP