`
jiagyao
  • 浏览: 99244 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

SQL Server学习笔记6之--排名函数和缺失 已有范围

阅读更多
1.排名函数:
SQL2005引进了4个新的排序函数,分别是 row_number  rank dense_rank ntile .我不知道怎么排版写,就散乱地写点吧。

a.row_number :
row_number()不仅在排名上有作用,而且在许多实际问题上都有不错的应用,效率也非常不错.
排名函数 就是用来为记录添上编号--行号。这里说个分区排名的用法的内在介绍吧
row_number() over(partition by col1 order by col2)
这里就是需要先按分区列再按排序列对数据排序。 你看执行计划,会发现一个叫系列摄影的运算符号,它负责计算排名值.对于表中的每条记录,她要检查2个方面.
1) 该行是否为分区的第一行? 意思就是检查你COL1列的值和上一个PARTITION BY的值是否相同。如果不同,就说明它是第一行,那么返回一个TRUE;
否则返回FALSE;返回TRUE就要重新排名,从1开始.普通的ROW_NUMBER() 没有分区 那么它只有第一行为TRUE 其他都是false,则一直排序下去。
2) 该行是否不同于上一个值?意思就是和上面一个值比较.就相当于在一个分区内根据条件的排序规则排序。这里的ROW_NUMBER 是一定会为每行递增下去的,
但是RANK DECSE_RANK是会经过判断后,决定是否递增的.
介绍几个情况:
SET NOCOUNT ON;
USE tempdb;
GO
IF OBJECT_ID('dbo.Sales') IS NOT NULL
  DROP TABLE dbo.Sales;
GO
CREATE TABLE dbo.Sales
(
  empid VARCHAR(10) NOT NULL PRIMARY KEY,
  mgrid VARCHAR(10) NOT NULL,
  qty   INT         NOT NULL
);
INSERT INTO dbo.Sales(empid, mgrid, qty) VALUES('A', 'Z', 300);
INSERT INTO dbo.Sales(empid, mgrid, qty) VALUES('B', 'X', 100);
INSERT INTO dbo.Sales(empid, mgrid, qty) VALUES('C', 'X', 200);
INSERT INTO dbo.Sales(empid, mgrid, qty) VALUES('D', 'Y', 200);
INSERT INTO dbo.Sales(empid, mgrid, qty) VALUES('E', 'Z', 250);
INSERT INTO dbo.Sales(empid, mgrid, qty) VALUES('F', 'Z', 300);
INSERT INTO dbo.Sales(empid, mgrid, qty) VALUES('G', 'X', 100);
INSERT INTO dbo.Sales(empid, mgrid, qty) VALUES('H', 'Y', 150);
INSERT INTO dbo.Sales(empid, mgrid, qty) VALUES('I', 'X', 250);
INSERT INTO dbo.Sales(empid, mgrid, qty) VALUES('J', 'Z', 100);
INSERT INTO dbo.Sales(empid, mgrid, qty) VALUES('K', 'Y', 200);
CREATE INDEX idx_qty_empid ON dbo.Sales(qty, empid);
CREATE INDEX idx_mgrid_qty_empid ON dbo.Sales(mgrid, qty, empid);
如果有唯一的列只根据EMPID排序)
2000:
SELECT empid,
  (SELECT COUNT(*)
   FROM dbo.Sales AS S2
   WHERE S2.empid <= S1.empid) AS rownum
FROM dbo.Sales AS S1
ORDER BY empid;
2005:
select empid,
rownum=ROW_NUMBER() over(order by empid)
from Sales
--顺便提下:通过执行计划你可以清楚看到后者强烈的优势
如果只有一列不够唯一,需要加附加列来确定唯一的排名(根据qty,empid排序)
--2000
SELECT empid, qty,
  (SELECT COUNT(*)
   FROM dbo.Sales AS S2
   WHERE S2.qty < S1.qty
      OR (S2.qty = S1.qty AND S2.empid <= S1.empid)) AS rownum
FROM dbo.Sales AS S1
ORDER BY qty, empid;
--2005
select
empid,qty,
rownum=ROW_NUMBER()over(order by qty,empid)
from Sales
--顺便提下:通过执行计划你可以清楚看到后者强烈的优势
如果只有一列,而且没有附加的列
IF OBJECT_ID('dbo.T1') IS NOT NULL
  DROP TABLE dbo.T1;
GO
CREATE TABLE dbo.T1(col1 VARCHAR(5));
INSERT INTO dbo.T1(col1) VALUES('A');
INSERT INTO dbo.T1(col1) VALUES('A');
INSERT INTO dbo.T1(col1) VALUES('A');
INSERT INTO dbo.T1(col1) VALUES('B');
INSERT INTO dbo.T1(col1) VALUES('B');
INSERT INTO dbo.T1(col1) VALUES('C');
INSERT INTO dbo.T1(col1) VALUES('C');
INSERT INTO dbo.T1(col1) VALUES('C');
INSERT INTO dbo.T1(col1) VALUES('C');
INSERT INTO dbo.T1(col1) VALUES('C');

--2000
SELECT number + smaller AS rownum, col1
FROM (SELECT col1, COUNT(*) AS dups,
        (SELECT COUNT(*) FROM dbo.T1 AS B
         WHERE B.col1 < A.col1) AS smaller
      FROM dbo.T1 AS A
      GROUP BY col1) AS D, master..spt_values
WHERE number <= dups and type='p'
order by col1
--2005
select col1,
rownum=ROW_NUMBER() over(order by col1 )
from t1
可能大家发现了一个东西我没写 IDENTITY.它其实是2005之前一个计算行号非常常用效率也很高的方法.
一般的思路就是:通过IDENTITY带着数据放入一个临时表,之后就可以用行号了,就是多了个临时表.
当然你也可以用游标处理:
DECLARE @SalesRN TABLE(empid VARCHAR(5), qty INT, rn INT);
DECLARE @empid AS VARCHAR(5), @qty AS INT, @rn AS INT;
BEGIN TRAN
DECLARE rncursor CURSOR FAST_FORWARD FOR
  SELECT empid, qty FROM dbo.Sales ORDER BY qty, empid;
OPEN rncursor;
SET @rn = 0;
FETCH NEXT FROM rncursor INTO @empid, @qty;
WHILE @@fetch_status = 0
BEGIN
  SET @rn = @rn + 1;
  INSERT INTO @SalesRN(empid, qty, rn) VALUES(@empid, @qty, @rn);
  FETCH NEXT FROM rncursor INTO @empid, @qty;
END
CLOSE rncursor;
DEALLOCATE rncursor;
COMMIT TRAN
SELECT empid, qty, rn FROM @SalesRN;
--关于游标应该尽量避免使用,因为它包含太多的开销.当然在分区非常小,它的速度也会非常快。一般表越小,它的速度也越快。
经过书上测试:这几个方法排序是->row_number()<identity<cursor<2000的子查询
b.RANK ,Dense RANK,NTILE
它们分别用于排名 积分应用 计算百分比或组中排列各个元素
它们区别我直接给出例子,就可以很清楚的看到
create table rankorder(
orderid int,
qty int
)
go
--插入数据
insert rankorder values(30,10)
insert rankorder values(10,10)
insert rankorder values(80,10)
insert rankorder values(40,10)
insert rankorder values(30,15)
insert rankorder values(30,20)
insert rankorder values(22,20)
insert rankorder values(21,20)
insert rankorder values(10,30)
insert rankorder values(30,30)
insert rankorder values(40,40)
go
SELECT orderid,qty,
  ROW_NUMBER() OVER(ORDER BY qty) AS rownumber,
  RANK()       OVER(ORDER BY qty) AS [rank],
  DENSE_RANK() OVER(ORDER BY qty) AS denserank ,
  NTILE(3) OVER(ORDER BY qty) AS [NTILE]
FROM rankorder
ORDER BY qty
--结果
--ROW_NUMBER()是按qty由小到大逐一排名,不并列,排名连续
--RANK()是按qty由小到大逐一排名,并列,排名不连续
--DENSE_RANK()是按qty由小到大逐一排名,并列,排名连续
--NTILE()是按qty由小到大分成3组逐一排名,并列,排名连续
/*
orderid    qty    rownumber    rank    denserank    NTILE
30        10    1            1        1            1
10        10    2            1        1            1
80        10    3            1        1            1
40        10    4            1        1            1
30        15    5            5        2            2
30        20    6            6        3            2
22        20    7            6        3            2
21        20    8            6        3            2
10        30    9            9        4            3
30        30    10           9        4            3
40        40    11           11       5            3*/

2.已有范围和缺失范围
这是一个很实际的问题,偷懒下,我直接用书上的数据了.
USE tempdb;
GO
IF OBJECT_ID('dbo.T1') IS NOT NULL
  DROP TABLE dbo.T1
GO
CREATE TABLE dbo.T1(col1 INT NOT NULL PRIMARY KEY);
INSERT INTO dbo.T1(col1) VALUES(1);
INSERT INTO dbo.T1(col1) VALUES(2);
INSERT INTO dbo.T1(col1) VALUES(3);
INSERT INTO dbo.T1(col1) VALUES(100);
INSERT INTO dbo.T1(col1) VALUES(101);
INSERT INTO dbo.T1(col1) VALUES(103);
INSERT INTO dbo.T1(col1) VALUES(104);
INSERT INTO dbo.T1(col1) VALUES(105);
INSERT INTO dbo.T1(col1) VALUES(106);
--首先要看的是缺失范围的查询:
--方法1:找出断点的第一个数字后,找出距离这个断点数字最近的数字-1(关于找出缺失数字我前面的学习笔记有介绍了几种方法)
select col1+1 as startnum,
(select MIN(col1)-1 from T1 where k.col1<col1) as endnum
from T1 k
where not exists(select * from T1 where k.col1+1=col1)
and col1<(select MAX(col1) from T1)--防止最大数字的后一个数字出现
--方法2:利用前后2个数字相减的差来判断是否连续
select CUr+1 as stratnum,nxt-1 as endnum
from(
select col1 as cur,(select MIN(col1) from T1 where k.col1<col1) as nxt
from T1 k) p
where nxt-cur>1
/*
stratnum    endnum
----------- -----------
4           99
102         102
*/
--再来看看已有范围的查询
--方法1:利用比当前值大的最接近最小间断值的值
select MIN(col1) as startnum,
grp as endnum
from(
select col1,
(select MIN(col1) from T1 a where a.col1>=k.col1 and
    not exists(select * from T1 where a.col1+1=col1 )) as grp
from T1 k ) z
group by grp
--方法2:利用ROW_NUMBER 以前看P梁写过,就是产生一个分组因子(上面那个方法是通过子查询来确定一个分组因子其实)
select MIN(col1) as startnum,
max(col1) as endnum
from(
select col1,
col1-ROW_NUMBER()over(order by col1) as grp
from T1 k ) z
group by grp
/*
startnum    endnum
----------- -----------
1           3
100         101
103         106
*/
分享到:
评论

相关推荐

    Microsoft SQL Server 2008技术内幕:T-SQL查询

    主要内容包括SQL的基础理论、查询优化、查询算法及复杂度,以及在使用子查询、表表达式、排名函数、数据聚合和透视转换、TOP和APPLY、数据修改、分区表、特殊数据结构等实际应用时会遇到的各种高级查询问题和解决...

    sql server 2005 技术内幕t-sql查询源码

    6. **触发器与函数**:讨论触发器(TRIGGER)的原理和应用,以及用户自定义函数(UDF),包括标量函数和表值函数的创建和使用。 7. **高级查询技巧**:可能涵盖窗口函数(ROW_NUMBER、RANK、DENSE_RANK等)、递归...

    sql server学习手册以及t-sql优化方案.zip

    《SQL Server学习手册》与T-...通过深入阅读《SQL Server学习手册》并实践其中的T-SQL优化方案,无论是初学者还是有经验的开发者,都能进一步提升在SQL Server 2008平台上的技能和效率,为企业的数据管理打下坚实基础。

    Microsoft SQL SERVER 2008技术内幕 T-SQL查询

    主要内容包括SQL 的基础理论、查询优化、查询算法及复杂度,以及在使用子查询、表表达式、排名函数、数据聚合和透视转换、TOP 和APPLY、数据修改、分区表、特殊数据结构等实际应用时会遇到的各种高级查询问题和解决...

    SQL SERVER学习笔记

    根据提供的文件内容,我们可以整理出一系列关于SQL Server的基础知识点,主要涵盖了数据库的创建与删除、表的创建与修改、数据的插入与更新、以及查询语句等关键操作。下面将详细解析这些知识点。 ### 1. 数据库的...

    T-SQL性能调优秘笈 基于SQL Server 2012窗口函数_PDF电子书

    - **窗口函数概述**:窗口函数(Window Function)是在SQL Server中处理复杂查询的一种强大工具,它可以用来执行分组内的计算,如排名、行号、累计总和等操作。 - **常见的窗口函数**: - `ROW_NUMBER()`:为每一行...

    SQLServer2005数据库学习笔记

    笔记是本人学习SQLServer一段时间后重新整理出来的,适合有一些入门基础的人学习。 ├─01 安装及使用 │ SQLServer2005安装及使用.txt │ ├─02 常用函数 │ function.sql │ ├─03 建表、建库 │ create.sql ...

    Microsoft SQL Server 2008技术内幕:T-SQL查询.pdf

    6. **窗口函数**:SQL Server 2008引入了窗口函数,如RANK、ROW_NUMBER、LEAD和LAG,这些函数允许在结果集上执行行级别的计算,为复杂的数据分析提供了便利。 7. **T-SQL流程控制**:IF...ELSE、WHILE、CASE表达式...

    sql server 2012 T-SQl基础教程 源码和示例数据库

    《SQL Server 2012 T-SQL基础教程——源码与示例数据库》 本教程专注于Microsoft SQL Server 2012中的Transact-SQL...通过系统学习和动手实践,你将能够编写出高效的T-SQL查询,管理和操作SQL Server 2012中的数据。

    Inside Microsoft SQL Server 2008 T-SQL Programming.pdf

    - **函数**:探讨了标量函数和表值函数的区别,以及如何在T-SQL中使用自定义函数来增强查询的灵活性和重用性。 - **事务处理**:阐述了事务的基本概念及其在SQL Server中的实现方式,包括如何使用BEGIN TRANSACTION...

    Sql Server2005对t-sql的增强之排名函数

    在SQL Server 2005中,T-SQL得到了显著的增强,特别是在排名函数方面。这一增强使得数据处理和分析更为高效和灵活。排名函数主要包括ROW_NUMBER、RANK、DENSE_RANK以及NTILE,它们各自有着不同的应用场景和功能。 1...

    SQLServer2000常用函数大全-经典

    这份“SQLServer2000常用函数大全-经典”压缩包文件,显然是一份全面的资源,包含了SQL Server 2000中广泛使用的各种函数及其经典应用实例,对初学者和专业人士都有很高的学习价值。 首先,我们要了解SQL Server ...

    Microsoft SQL Server 2008技术内幕:T-SQL查询_源代码及附录.zip

    《Microsoft SQL Server 2008技术内幕:T-SQL查询》是一本深入探讨SQL Server 2008中T-SQL(Transact-SQL)查询的权威书籍。T-SQL是SQL Server数据库管理系统的核心语言,用于数据操作、查询、存储过程编写以及...

    Sqlserver2008--学习笔记(自己总结)

    ### Sqlserver2008 学习笔记精要 #### 第一章 SQL Server 基础 ##### 1. T-SQL 语句基础 - **创建数据库**: 使用 `CREATE DATABASE` 语句来创建一个新的数据库。例如: ```sql CREATE DATABASE 新数据库名; ``...

    sqlserver个人学习笔记

    ### SQLServer个人学习笔记知识点概览 #### 一、日期格式转换:`SELECT REPLACE(CONVERT(CHAR(8),GETDATE(),120),'-','')` - **知识点**:使用`CONVERT`函数将当前系统时间`GETDATE()`转换为指定格式的字符串,并...

    SQL server-2017-学习笔记.docx

    在SQL Server 2017的学习中,我们首先需要了解SQL Server的基础操作,这包括了基本的增删改查操作,比如INSERT、DELETE、UPDATE和SELECT。这些是数据库管理中最常用的操作,用于处理数据的存取和修改。 接着,我们...

    Inside Microsoft SQL Server 2008 T-SQL Programming

    《Inside Microsoft SQL Server 2008 T-SQL Programming》这本书深入探讨了SQL Server 2008中的T-SQL编程技术,这是SQL Server数据库管理与开发的核心语言。T-SQL,即Transact-SQL,是SQL的一个扩展,主要用于微软的...

    T-SQL性能调优秘笈-基于SQL Server 2012窗口函数

    T-SQL性能调优秘笈-基于SQL Server 2012窗口函数,适合数据库进阶。

Global site tag (gtag.js) - Google Analytics