• SqlServer 语法


    四、            Ranking

    排序与排名是我们最为常用的统计方式,比如对班级的学生根据成员进行排名,或者按照成绩高低把学生划分成若干梯队:比如最好成绩的10名学生属于第一梯队,后10名又划分为第二梯队,以此类推。Ranking设计的Key Words包括:ROW_NUMBER(),RANK(),DENSE_RANK(),NTILE()我们现在就来介绍一下他们的用法和相互之间的差异。

    1.          1. ROW_NUMBER()

    看到ROW_NUMBER(),我想绝大多数人会像想到Oracle的ROWNUM。他们的作用相似,都是表示某条记录所处的Index。ROW_NUMBER()比Oracle的ROWNUM更加强大的是,它可以通过OVER语句指定一个进行排序的Column,比如:ROW_NUMBER() OVER (ORDER BY CustomerID)。

    我们来看一个例子:对Sales.SalesOrderHeader按照CustomerID进行排序,并显示每条记录的Row Number。

    SELECT SalesOrderID,CustomerID,ROW_NUMBER() OVER (ORDER BY CustomerID) AS RowNum
    FROM Sales.SalesOrderHeader

    下面是查询结果:



    我们发现最终的结果按照CutomerID进行排序,RowNum从1开始以此递增,每条记录(不管是否具有相同的CustomerID)拥有不同的RowNum。

    提到排序,我们就不得不提到Order BY,如果我们在后面加上ORDER BY,并指定不同的排序字段,会出现怎样的结果呢?

    SELECT SalesOrderID,CustomerID,ROW_NUMBER() OVER (ORDER BY CustomerID) AS RowNum
    FROM Sales.SalesOrderHeader
    ORDER BY SalesOrderID

    查询获得的结果是:



    从上图中可以看到,最终的结果以ORDER BY中指定的SalesOrderID进行排序,但是ROW_NUMBER()体现的值却是基于CustmerID排序的。

    由于ROW_NUMBER()体现是基于某个确定的字段进行排序后某个DataRow所处的位置,所以它不能直接使用到Aggregate的Column中。比如下面的SQL是不合法的:

    SELECT CustomerID,COUNT(*) AS OrderCount,ROW_NUMBER() OVER (ORDER BY OrderCount)
    FROM Sales.SalesOrderHeader
    GROUP BY CustomerID

    要是想按照OrderCount,可以使用第一部分介绍的CTE:

    WITH CTE_Order(CustomerID,OrderCount)
    AS
    (
    SELECT CustomerID,COUNT(*) AS OrderCount
    FROM Sales.SalesOrderHeader
    GROUP BY CustomerID
    )

    SELECT CustomerID,OrderCount,ROW_NUMBER() OVER (ORDER BY OrderCount)
    FROM CTE_Order

    2.          RANK()

    RANK()的使用和ROW_NUMBER()类似。不过它与ROW_NUMBER()所不同的是:对于被指定为排序的字段,具有相同值得Row对应的返回值相同。比如:

    SELECT SalesOrderID,CustomerID,RANK() OVER (ORDER BY CustomerID) AS RowNum
    FROM Sales.SalesOrderHeader

    下面是相应的查询结果:



    对于RANK(),还有一点需要说明的是,它的回返值不是连续的, 比如第五条记录的Row_Num是5而不是2。如果想实现这样需求,就需要用下面一个Function:DENSE_RANK()。

    3.          3. DENSE_RANK()

    DENSE_RANK()实现了一个连续的Ranking。比如下面的SQL:

    SELECT SalesOrderID,CustomerID,DENSE_RANK() OVER (ORDER BY CustomerID) AS RowNum
    FROM Sales.SalesOrderHeader

    就来产生如下的查询结果:


    4. NTILE()

    上面我们说到划分梯队的问题,这样的问题可以通过NTILE() Function来实现。比如我们现在按照CustomerID排序,把CustomerID为1和2的划分到3梯队中:

    SELECT SalesOrderID,CustomerID,NTILE(3) OVER (ORDER BY CustomerID) AS RowNum
    FROM Sales.SalesOrderHeader
    WHERE CustomerID <3

    其查询结果为:



    我们可以看到,一共12条记录,划分为3组,平均下来每组4条记录。

    5.          5.PARTITION BY

    上面提到的所有Ranking都是基于真个结果基的。而有的时候我们需要将真个结果集按照某个Column 进行分组,进行基于组的Ranking。这就需要PARTITION BY了。PARTITION BY置于OVER Clause中,和ORDER BY 平级。

    比如下面的SQL将Order记录按照CustomerID进行分组,在每组中输出排名(安OrderDate排序):

    SELECT SalesOrderID,CustomerID,RANK() OVER (PARTITION BY CustomerID ORDER BY OrderDate) AS RowNum
    FROM Sales.SalesOrderHeader

    相应的查询结果:

  • 相关阅读:
    PHP设计模式——观察者模式
    TRIZ系列-创新原理-34-抛弃和再生部件原理
    玩转Android Camera开发(三):国内首发---使用GLSurfaceView预览Camera 基础拍照demo
    高速排序算法C++实现
    crm操作报价单实体
    CSS3 网格布局(grid-layout)基础知识
    shadowOffset 具体解释
    [软件人生]关于此次抄袭事件的一个对话
    SpringMVC接收复杂集合对象(参数)代码示例
    Spring MVC同时接收一个对象与List集合对象
  • 原文地址:https://www.cnblogs.com/a14907/p/6780930.html
Copyright © 2020-2023  润新知