• 【译】高级T-SQL进阶系列 (七)【上篇】:使用排序函数对数据进行排序


    【译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正】

    原文链接:传送门

    什么是排序函数(Ranking Functions)?

            排序函数基于一组记录的集合返回一个排序值。一个排序值其实就是一个数字,典型的它都是从1开始并且对于每一个新的排序值它都是按1递增的。根据排序函数的不同,对于数据集中的每一行来说,返回的排序值有可能是唯一的,或者一些数据行会具有一样的排序值。在接下来的章节中,我将浏览下这些不的排序函数,以及它们是如何使用的。

    使用排序函数(Ranking Function)的例子

            在一个分区中每行的排序数字都是从1开始递增的。在一个排序函数中,一个“分区”指的其实就是一组数据行,它们对于指定的分区列具有相同的值(因而把它们归为一个分区)。如果对于一个分区的两行它们的排序列(在ORDER BY 中指定的列)具有相同的值,那么它们两个都会得到相同的排序值。为了更好的理解如何 使用Rank函数,让我们看看它的句法:

    RANK ( ) OVER ( [ PARTITION BY <partition_column> ] ORDER BY <order_by_column> )

    其中:

    • <partition_column>:定义了一个或者多个列名,它们将用来对数据进行分区;
    • <order by column>:定义了一个或者多个列表,它们将用来对各个分区的输出进行排序;

    注意:

            PARTITION BY子句是可选的。如果没有使用  PARTITION BY子句,那么数据会基于一个分区进行排序。如果你在Rank函数中指定了PARTITION BY子句,那么对于数据集中的每个分区排序值都会被重置为1的。

            既然现在你已经了解了Rank函数是做什么的,以及它的句法,那么我会运行几个Rank函数的例子。我所有的例子都会使用AdventureWorks2012数据库。如果你想跟着我的示例,那么你可以从下列位置下载 AdventureWorks2012数据库:http://msftdbprodsamples.codeplex.com/releases/view/93587

    对于我使用Rank函数的第一个例子,让我来运行下面的代码:

    USE AdventureWorks2012;
    GO
    SELECT PostalCode, StateProvinceID,
           RANK() OVER 
             (ORDER BY PostalCode ASC) AS RankingValue
    FROM Person.Address 
    WHERE StateProvinceID IN (23,46);

      列表1:简单的Rank函数的例子

             当我运行列表1的代码,我得到了结果1的输出:

    PostalCode      StateProvinceID RankingValue
    --------------- --------------- --------------------
    03064           46              1
    03064           46              1
    03106           46              3
    03276           46              4
    03865           46              5
    83301           23              6
    83402           23              7
    83501           23              8
    83702           23              9
    83864           23              10

    结果1: 当运行列表1的代码产生的输出

            如果你查看结果1的输出,你可以看到由Rank函数产生的值在RankingValue列中。在这个例子中,我是基于PostalCode列进行排序的。每一个唯一的PostalCode值都会得到一个不同的排序值。如果你查看输出的结果行,对于PostalCode 03064,你将会看到两行,其中每一行都有一个排序值1。因为有两个PostalCode为03064的数据行,排序值2便被跳过了。对于PostalCode 03106,其排序值便会为3。剩下的RankingValue值会按次序进行分配,因为它们的PostalCode值都是唯一的。

           因为Rank函数的PARTITION BY子句没有被用在列表1中,整个数据集被认为是一个单独的分区。如果我想对于每一个唯一的StateProvinceID值来重新开始我的RankingValue值,那么我必须要做的所有的事情便是基于StateProvinceID对我的结果进行分区,在列表2中我以PostalCode进行排序并以StateProvinceID进行分区。

    USE AdventureWorks2012;
    GO
    SELECT PostalCode, StateProvinceID,
           RANK() OVER 
             (PARTITION BY StateProvinceID
              ORDER BY PostalCode ASC) AS RankingValue
    FROM Person.Address 
    WHERE StateProvinceID IN (23,46);

    列表2:使用PARTITION BY子句

           当我运行列表2的代码,我得到了结果2的输出。

    PostalCode      StateProvinceID RankingValue
    --------------- --------------- --------------------
    83301           23              1
    83402           23              2
    83501           23              3
    83702           23              4
    83864           23              5
    03064           46              1
    03064           46              1
    03106           46              3
    03276           46              4
    03865           46              5

     结果2:当运行列表2的输出

            在列表2的输出有两个分区。一个分区包含了所有的StateProvinceID值为23的PostalCode值,第二个分区包含了StateProvinceID为46的PostalCode值。注意对每一个分区来说RankingValue都是从1开始的。

    使用稠密排序(DENSE RANK)函数的例子

            当我对每个重复的PostalCode值运行Rank函数,我的输出便会跳过一个RankingValue值。

            通过使用DENSE RANK函数,我会生成一个不会跳过任何值的排序值。DENSE RANK函数具有如下的句法:

    DENSE_RANK ( ) OVER ( [ PARTIION BY <partition_column> ] ORDER BY <order_by_column> )

    其中:

    • <partition_column>:定义了一个或者多个列名,其用来对数据进行分区。
    • <order_by_column>: 定义了一个或者多个列名,其用来对各个分区的输出进行排序。

            在句法上RANK 函数和 DENSE RANK函数唯一的不同其实就是函数名的不同而已。

            为了浏览DENSE RANK函数让我来运行列表3的代码:

    USE AdventureWorks2012;
    GO
    SELECT PostalCode, StateProvinceID,
           DENSE_RANK() OVER 
             (PARTITION BY StateProvinceID
              ORDER BY PostalCode ASC) AS RankingValue
    FROM Person.Address 
    WHERE StateProvinceID IN (23,46);

    列表3:使用DENSE_RANK

           当我运行列表3的代码,我得到了结果3的输出:

    PostalCode      StateProvinceID RankingValue
    --------------- --------------- --------------------
    83301           23              1
    83402           23              2
    83501           23              3
    83702           23              4
    83864           23              5
    03064           46              1
    03064           46              1
    03106           46              2
    03276           46              3
    03865           46              4

    结果3:运行列表3产生的输出

           通过查看结果3的输出你会看到PostalCode为03064的数据行具有相同的RankingValue值。但是下一个PostalCode具有一个排序值2而不是3。记住在结果2中RANK函数对于这个相同的重复PostalCode其跳过了一个RankingValue值。使用DENSE_RANK函数,当遇到一个重复的PostalCode值时,它不会跳过一个RankingValue值。相反的,甚至当遇到重复的排序行值时,它会保证所有的RankingValue值都是连续的。

    (To be continued...)

  • 相关阅读:
    在其他博客里看到的比较好的map用法,进行储存啦啦~ x
    codevs 2597 团伙x
    codevs 1009 产生数x
    格子游戏x(并查集)
    codevs 5929 亲戚x
    [HDOJ2389]Rain on your Parade(二分图最大匹配,HK算法)
    [HDOJ2819]Swap(二分图最大匹配, 匈牙利算法)
    [HDOJ1281]棋盘游戏(二分图最大匹配,匈牙利算法)
    [HDOJ1083]Courses(二分图最大匹配,匈牙利算法)
    [HDOJ2444]The Accomodation of Students(二分图染色判定,最大匹配,匈牙利算法)
  • 原文地址:https://www.cnblogs.com/qianxingmu/p/12259674.html
Copyright © 2020-2023  润新知