• SQL Server递归查询和分页


    圣诞快乐!好久没来写了,最近比较忙乱。今天放假在家休息了一天,就发一篇吧,以后还是要坚持写。

    SQL Server 2005 中新支持了递归查询和row_number()函数。这些已经不是新话题了。只是在工作中遇到一个需求,要显示分类的新闻,并且支持分页。其中,新闻的分类是支持无限级的分类,因此这两个新特性就能够很好的完成这项工作。本来考虑到虚拟空间服务商提供的数据库可能是2000,不过现在看看很多都是2005的了,也就不再考虑兼容性的问题。

    先看递归查询,递归查询特别适合获取层次类型的数据。例如,一个分类下的所有新闻(包括子分类)。SQL Server中可以利用公用表表达式(CTE)实现递归查询。其语法形式为:

    WITH cte_name ( column_name [,...n] )
    AS
    (
    CTE_query_definition –- Anchor member is defined.
    UNION ALL
    CTE_query_definition –- Recursive member is defined referencing cte_name.
    )
    -- Statement using the CTE
    
    SELECT *
    FROM cte_name

    递归执行的语义如下:

    1. 将 CTE 表达式拆分为定位点成员和递归成员。
    2. 运行定位点成员,创建第一个调用或基准结果集 (T0)。
    3. 运行递归成员,将 Ti 作为输入,将 Ti+1 作为输出。
    4. 重复步骤 3,直到返回空集。
    5. 返回结果集。这是对 T0 到 Tn 执行 UNION ALL 的结果。

    SQL的递归和普通语言的递归函数差不多,只是普通函数通常是返回一个值,SQL返回的是一张表,并且它将所有表的结果联合到一起返回。 下面看一个具体的例子,有如下两张表,分别表示新闻和新闻分类。新闻分类采用层次结构,利用ParentID关联。

    CREATE TABLE [dbo].[Post](
    	[ID] [int] IDENTITY(1,1) PRIMARY KEY NOT NULL,
    	[Title] [nvarchar](500),
    	[Content] [ntext],
    	[CategoryID] [int] NOT NULL,
            [CreateTime] datetime DEFAULT(getdate()),
    	[IsDelete] [bit] NULL 
    ) ON [PRIMARY] 
     
    CREATE TABLE [dbo].[PostCategory](
    	[ID] [int] IDENTITY(1,1) NOT NULL,
    	[Name] [nvarchar](500),
    	[Description] [nvarchar](500),
    	[ParentID] [int] NULL, 
    	[Level] [int] NOT NULL
    ) ON [PRIMARY]

    我们写一个查询,返回所有属于某个分类的新闻(包括子分类)。例如返回ID是1的分类的所有新闻。首先我们要查找到分类号1的分类,然后递归的找出parentID是1的分类,最后和Post表进行连接即可。因此,查询代码如下:

    with t as( 
    select  postcategory.ID from postcategory where id=1
    union all
    select postcategory.ID from t join postcategory on t.ID=postcategory.parentID
    )
    select * from t join post on post.categoryID=t.ID
    where isDelete=0

    下面介绍row_number()函数,row_number()函数可以为返回的查询结果加上一列行号。其语法形式是:

    ROW_NUMBER ()     OVER ( [ <partition_by_clause> ] <order_by_clause> )

    其中,order by 子句指定根据什么顺序编号,partition by 子句可以按某一字段聚合,使得对那个字段的不同的值分别编号。说起来比较拗口,看一个例子就十分明了了。比较下面三个查询:

    select  Title,[Content],categoryID from post
    select Title,[Content],categoryID,row_number() over(order by [title]) from post
    select Title,[Content],categoryID,row_number() over(partition by categoryID order by [title]) from post

    其查询结果如下:

    sql

    言归正传,现在把两者结合起来,就可以实现分页了:

    with t as( 
    select postcategory.ID from postcategory where id=1
    union all
    select postcategory.ID from t join postcategory on t.ID=postcategory.parentID
    )
    select * from(
    select lite_post.ID,Title,[Content],row_number() over(order by CreateTime) as  rid  
    from t join post on post.categoryID=t.ID
    where isDelete=0  
    )a  where rid between 2 and 3

    这是一个例子,将最后的between的参数和id=1中的1替换成适当的参数,就写成一个存储过程供程序调用了。

    最后是题外话,这篇文章里用了Syntax Highlighter 来给代码着色,这是一个开源的javascript语法着色器,非常好用。我还是第一次知道,以前我都用paste from visual studio。 这个插件比较有点局限。这个js着色器虽然不是那么精准,不过也够用了。

  • 相关阅读:
    【转】EditText获取焦点不自动弹出键盘设置--失去焦点的方法,不错
    【转】eclipse android 设置及修改生成apk的签名文件 -- custom debug keystore
    【转】Adnroid4.0 签名混淆打包(conversion to dalvik format failed with error 1)
    【转】Android Fragment 基本介绍--不错
    【转】java代码中实现android背景选择的selector-StateListDrawable的应用
    【转】android官方侧滑菜单DrawerLayout详解
    【转】微信Android SDK示例代码及运行方法
    【转】Eclipse中设置ButterKnife进行注解式开发步骤 -- 不错
    【转】ButterKnife基本使用--不错
    python 命令行:help(),'more'不是内部或外部命令,也不是可运行的程序或批处理文件
  • 原文地址:https://www.cnblogs.com/yinzixin/p/1916891.html
Copyright © 2020-2023  润新知