SQLServer数据库分页
以 项目表 PM_Project 为例。
PM_Project 全部内容如下(共6条数据):

一、Top – Not In - Top 方式分页
直接的,原始的,不采用函数,纯手动挡。
分步探索过程:
采用的最直接做法就是使用两个Top来实现。
DECLARE @pageSize INT =4,@pageIndex INT =1
BEGIN
SELECT TOP (@pageSize)
*
FROM ( SELECT TOP (@pageSize * @pageIndex)
*
FROM PM_Project
ORDER BY Id DESC --- 内查询倒序
) AS temp
ORDER BY Id ---外查询正序, 内外查询顺序不一致即可
END
GO
结果:

乍一看是没有问题的,但是仔细一看会发现其中存在的问题。当符合条件的纪录集小于每页记录数时,没有问题,但是当大于就有问题了。
例如上边代码,实际满足条件的是6条,即全部满足(因为根本就没加条件)。第一页是没有问题的,但是第二页就有问题了。现在共6条数据,每页4条,按理说第二页应该只有2条。但是使用如上的方法,每次都会返回4条记录。
当pageIndex =2 时,结果如下:

沿用上面的思路,把代码修改为了采用三层查询,最内一层查询所有满足条件的数据,然后第二层选择Top PageSize个所有NOT IN 第一层数据中的数据即可,因为使用了NOT IN所以不存在第一种方法中的bug
DECLARE @pageSize INT =4,@pageIndex INT =2 ---直接看第二页
BEGIN SELECT *
FROM PM_Project
WHERE Id IN (
SELECT TOP ( @pageSize )
Id
FROM PM_Project
WHERE Id NOT IN ( SELECT TOP ( @pageSize * (@pageIndex-1) )---去除本页之前的所有id
Id
FROM PM_Project
ORDER BY Id)
ORDER BY PM_Project.Id)
ORDER BY PM_Project.Id ASC END
GO
结果:

二、ROW_NUMBER()的方式实现分页
语法:
ROW_NUMBER ( ) OVER ( [ PARTITION BY value_expression , ... [ n ] ] order_by_clause )
分步过程:
首先查询全部满足条件的数据,并使用 ROW_NUMBER() 函数,可以根据给定好的排序字段规则,为查询结果生成记录序号。
SELECT ROW_NUMBER() OVER (ORDER BY id) rownum,
*
FROM PM_Project
结果:(共6条数据)

然后用TOP()函数取出一页数据
DECLARE @pageSize INT =4,@pageIndex INT =1 ------每页4条,第一页
BEGIN SELECT TOP(@pageSize*@pageIndex)
ROW_NUMBER() OVER (ORDER BY id) rownum,
*
FROM PM_Project
END
GO
这样取第一页还是可以的,但是往后就会越来越多。现在将上边的查询作为内查询,再外查询中通过条件来控制获取页数问题。
策略很简单,首先我们选取包含要查页的数据,然后使用ROW_NUMER函数进行编号, 然后在外查询中指定rownum大于页起始记录即可。这种方式简单快捷。
DECLARE @pageSize INT =4,@pageIndex INT =2 ------每页4条,第二页
BEGIN
SELECT*FROM
(
SELECT TOP(@pageSize*@pageIndex)
ROW_NUMBER() OVER (ORDER BY id) rownum,*
FROM PM_Project
)temp
WHERE temp.rownum>(@pageSize*(@pageIndex-1))
END
GO
查询第二页的结果:

在 Sql Server 2000 之后的版本中,ROW_NUMBER() 这种分页方式一直都是很不错的,比起之前的游标分页,性能好了很多,因为 ROW_NUMBER() 并不会引起全表扫表,但是,语法比较复杂,并且,随着页码的增加,性能也越来越差。
三、使用CTE(common_table_expression,公用表表达式)的方式
使用很简单,就是把内查询放在CTE 里面。
DECLARE @pageSize INT =4,@pageIndex INT =2
BEGIN
WITH temp
AS ( SELECT TOP ( @pageSize * @pageIndex )
ROW_NUMBER() OVER ( ORDER BY id) AS rownum ,
*
FROM PM_Project
)
SELECT *
FROM temp
WHERE temp.rownum > ( @pageSize * ( @pageIndex - 1 ) )
ORDER BY temp.Id
END
GO
结果:

四、使用 OFFSET FETCH 子句分页
语法:
OFFSET { integer_constant | offset_row_count_expression } { ROW | ROWS }
FETCH { FIRST | NEXT } { integer_constant | fetch_row_count_expression } { ROW | ROWS } ONLY
从语法可以看出来 两个方法 后面不但能接 intege 类型的参数,还能接 表达式的,比如 1*2 +3 之类的,同时, Row 或者 Rows 是不区分大小写和单复数的。
SQL Server 2012及以后版本支持。
例句:
DECLARE @pageSize INT =4,@pageIndex INT =2
BEGIN SELECT*FROM PM_Project
ORDER BY Id
OFFSET ( @pageSize * ( @pageIndex - 1 )) ROWS
FETCH NEXT @pageSize ROWS ONLY END
GO
结果:

性能对比:
SQLServer数据库分页的更多相关文章
- Sqlserver数据库分页查询
Sqlserver数据库分页查询一直是Sqlserver的短板,闲来无事,想出几种方法,假设有表ARTICLE,字段ID.YEAR...(其他省略),数据53210条(客户真实数据,量不大),分页查询 ...
- MySQL、SqlServer、Oracle三大主流数据库分页查询
在这里主要讲解一下MySQL.SQLServer2000(及SQLServer2005)和ORCALE三种数据库实现分页查询的方法.可能会有人说这些网上都有,但我的主要目的是把这些知识通过我实际的应用 ...
- 【转载】Sqlserver数据库中无自增Id的情况下使用ROW_NUMBER()函数进行数据分页
在Sqlserver数据库中,如果查询表中含有自增长Id列,一般会采用select Top的方式来数据的分页操作.而实际上很多数据表设计的时候,不一定含有自增长Id列,那么数据库没有Id自增列的时候要 ...
- mysql / sqlserver / oracle 常见数据库分页
空闲时间里用着mysql学习开发测试平台和测试用具, 在公司里将可用的测试平台部署,将数据库换成sqlserver 巴望着能去用oracle的公司 mysql中的分页 limit是mysql的语法se ...
- MySQL、SqlServer、Oracle三大主流数据库分页查询 (MySQL分页不能用top,因为不支持)
一. MySQL 数据库 分页查询MySQL数据库实现分页比较简单,提供了 LIMIT函数.一般只需要直接写到sql语句后面就行了.LIMIT子 句可以用来限制由SELECT语句返回过来的数据数量,它 ...
- 浅谈SQL Server数据库分页
数据库分页是老生常谈的问题了.如果使用ORM框架,再使用LINQ的话,一个Skip和Take就可以搞定.但是有时由于限制,需要使用存储过程来实现.在SQLServer中使用存储过程实现分页的已经有很多 ...
- sqlserver 存储过程分页管理
-- =============================================-- Author: <Author:刘畅>-- Create date: <Cre ...
- Oracle、MySql、SQLServer数据分页查询
看过此博文后Oracle.MySql.SQLServer 数据分页查询,在根据公司的RegionRes表格做出了 SQLserver的分页查询语句: 别名.字段 FROM( SELECT row_nu ...
- SQL多表连接查询以及mysql数据库、sqlserver数据库常见不同点
mysql数据库表及数据准备语句: USE test; DROP TABLE IF EXISTS `teacher_table`; DROP TABLE IF EXISTS `student_tabl ...
随机推荐
- UUID生成随机字符串
import java.util.UUID; UUID.randomUUID().toString().replace("-", "") 生成的样子 ...
- U盘插入电脑3.0的口没有反应了,2.0的口就可以
如果驱动没有问题的话,很有可能是优盘硬件故障. 尝试解决办法: 1.使劲插(就是用力一插到底).... 2.插入三分之一,不过速度只能达到2.0的速度.
- 【Linux基础】tr命令替换和删除字符
1.tr命令 tr可以对来自标准输入的字符进行替换.压缩和删除,可以将一组字符变成另外一组字符.通过使用 tr,您可以非常容易地实现 sed 的许多最基本功能.您可以将 tr 看作为 sed 的(极其 ...
- 【Teradata】移动空间语句
1.移动10G空间从sysdba到dbc create database td_tmp_db from sysdba as perm=10E9; give td_tmp_db to "dbc ...
- CentOS 7下安装Python3.6
CentOS 7下安装Python3.6.4 CentOS 7下安装Python3.5 •安装python3.6可能使用的依赖 yum install openssl-devel bzip2-de ...
- UVA1620-Lazy Susan(思维+逆序对)
Problem UVA1620-Lazy Susan Accept: 81 Submit: 375Time Limit: 3000 mSec Problem Description There ar ...
- 第8章 java中的并发工具类
8.1 等待线程完成的CountDownLatch 作用:让一个线程等待其余线程完成之后在继续执行,如主线程等待开启服务的子线程执行完毕后主线程继续执行,类似于join.
- LeetCode练习2 两数相加
问题如下: 给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果,我们将这两个数相加起来,则会返回一个新的链表来 ...
- 极端恢复时用到的几个隐藏参数 Oracle hidden corruption recovery parameters
Oracle hidden corruption recovery parameters Note: Oracle hidden parameters are undocumented and uns ...
- SWIG 的应用(一)
用 C/C++ 扩展 Python. - 如果仅使用标准 C 库函数,则可以使用 Python 自带的 ctypes 模块,或者使用 cffi. - 如果要使用自定义 C/C++ 函数,又不怕写 wr ...