SQL Server下7种“数据分页”方案,全网最全
数据分页往往有三种常用方案。
第一种,把数据库中存放的相关数据,全部读入PHP/Java/C#代码/内存,再由代码对其进行分页操作(速度慢,简易性高)。
第二种,直接在数据库中对相关数据进行分页操作,再把分页后的数据输出给代码程序(速度中,简易性中)。
第三种,先把数据库中的相关数据全部读入“缓存”或第三方工具,再由代码程序对“缓存”或第三方工具中的数据进行读取+分页操作(速度快,简易性差)。
本文下面重点阐述上述【第二种】方案在SQL Server上的使用(其它种类数据库由于Sql语句略有差异,所以需要调整,但方案也类似)
1、ROW_NUMBER() OVER()方式(SQL2012以下推荐使用)
示例:
SELECT * FROM
(SELECT ROW_NUMBER() OVER(ORDER BY menuId) AS RowId,* FROM sys_menu ) AS r
WHERE RowId BETWEEN 1 AND 10
用子查询新增一列行号(ROW_NUMBER)RowId查询,比较高效的查询方式,只有在SQL Server2005或更高版本才支持。
BETWEEN 1 AND 10 是指查询第1到第10条数据(闭区间),在这里面需要注意的是OVER的括号里面可以写多个排序字段。
通用用法
--pageIndex 表示指定页
--pageSize 表示每页显示的条数
SELECT * FROM
(SELECT ROW_NUMBER() OVER(ORDER BY 排序字段) AS RowId,* FROM 表名 ) AS r
WHERE RowId BETWEEN ((pageIndex-1)*pageSize + 1) AND (pageIndex * PageSize)
2、offset fetch next方式(SQL2012及以上的版本才支持:推荐使用 )
示例:
--offset fetch next方式查询,最高效的查询方式,只有在SQL Server2012或更高版本才支持
SELECT * FROM sys_menu
ORDER BY menuId offset 0 ROWS FETCH NEXT 10 ROWS ONLY
offset 是跳过多少行,
next是取接下来的多少行,
句式 offset...rows fetch nect ..rows only ,注意rows和末尾的only 不要写漏掉了,并且这种方式必须要接着Order by XX 使用,不然会报错。
通用用法
--pageIndex 表示指定页
--pageSize 表示每页显示的条数
SELECT * FROM 表名
ORDER BY 排序字段 offset ((pageIndex - 1) * pageSize) ROWS FETCH NEXT pageSize ROWS ONLY
3、top not in方式 (不推荐)
示例:
--查询第11-20条记录
SELECT TOP 10 menuId, *
FROM sys_menu
WHERE menuId NOT IN (SELECT TOP 10 menuId FROM sys_menu)
这条语句的原理是先查询1-10条记录的ID,然后再查询ID不属于这1-10条记录的ID,并且只需要10条记录,因为每页大小就是10,
这就是获取到的第11-20条记录,这是非常简单的一种写法。
另外IN语句与NOT IN语句类似,这是NOT IN的写法,但是这种写法数据量大的话效率太低。
通用用法
--pageIndex 表示指定页
--pageSize 表示每页显示的条数
SELECT TOP pageSize menuId, *
FROM sys_menu
WHERE menuId NOT IN (SELECT TOP ((pageSize-1)*pageIndex) menuId FROM sys_menu)
4、通过升序与降序方式进行查询分页(不推荐)
示例:
--查询第11-20条记录
SELECT * FROM(
SELECT TOP 10 * FROM(
SELECT TOP 20 * FROM sys_menu ORDER BY menuId ASC)
AS TEMP1 ORDER BY menuId DESC)
AS TEMP2 ORDER BY menuId ASC
这条语句首先查询前20条记录,然后在倒序查询前10条记录(即倒数10条记录),
这个时候就已经获取到了11-20条记录,但是他们的顺序是倒序,所以最后又进行升序排序。
通用方法
--pageIndex 表示指定页
--pageSize 表示每页显示的条数
SELECT * FROM(
SELECT TOP pageSize * FROM(
SELECT TOP ((pageIndex - 1) * pageSize +(pageSize*2)) * FROM sys_menu ORDER BY menuId ASC)
AS TEMP1 ORDER BY menuId DESC)
AS TEMP2 ORDER BY menuId ASC
5、采用MAX(ID)或者MIN(ID)函数(不推荐)
示例:
--查询第11-20条记录
SELECT TOP 10 * FROM sys_menu WHERE menuId>
(SELECT MAX(menuId) FROM(SELECT TOP 10 menuId FROM sys_menu ORDER BY menuId) AS TEMP1) --(第10条的id)
这个理解起来也简单,先把第10条记录的id找出来(当然这里面是直接使用MAX()进行查找,MIN()函数的用法也是类似的),
然后再对比取比第10条记录的id大的前10条记录即为我们需要的结果。
这里要注意开始时的边界值调整。
通用用法
--pageIndex 表示指定页
--pageSize 表示每页显示的条数
SELECT TOP pageSize * FROM sys_menu WHERE menuId>
(SELECT MAX(menuId) FROM(SELECT TOP ((PageIndex-1)*PageSize) menuId FROM sys_menu ORDER BY menuId) AS TEMP1) --(第10条的id)
上述1~5方案,再配合存储过程,你就能制造出适合你自己的“分页”轮子,日后反复使用。
但它们有一定自身局限性:方案1、2、5都需要依赖一个排序Id(这个Id要么是个排序列,要么是个主键)。方案3、4则效率太低,完全不推荐。
7、不依赖排序/排序Id的终极方案
此方案在DeveloperSharp框架中有提供(基于.Net/.Net Core/.Net Framework),方案被广东省的多个公司/项目采用,得到了实战验证+稳定性。
【第一步】:从NuGet引用DeveloperSharp包。
【第二步】:创建一个用来与数据库进行通信的“数据源类”(文本示例为:TestData.cs),内容如下:
using DeveloperSharp.Structure.Model;
using DeveloperSharp.Framework.QueryEngine; namespace YZZ
{
[DataSource(DatabaseType.SQLServer, "Server=localhost;Database=Test;Uid=sa;Pwd=123")]
public class TestData : DeveloperSharp.Structure.Model.DataLayer
{
//类中没有任何代码
}
}
说 明 :“数据源类”(文本示例为:TestData.cs)必 须 继 承 自 DeveloperSharp.Structure.Model.DataLayer 类 , 并 且 在 其 上 设 置DataSource属 性 的 初 始 化 值 为“数据库类型”及其“链接字符串”。
【第三步】:添加通过“数据源类”(TestData)调用其PagePartition方法进行数据分页的代码。注 意:核心代码就一行而已!!
代码如下:
using DeveloperSharp.Extension;//Table扩展所在的命名空间
-----------------------------
class Program
{
static void Main(string[] args)
{
TestData td = new TestData(); //分页
var pp = td.PagePartition("select top 5000 * from t_Order where Id>10 order by Id desc", 20, 162); List<Product> Products = pp.Table.ToList<Product>();
foreach (var P in Products)
{
Console.WriteLine(P.Name);
} Console.ReadLine();
}
}
Product类代码如下:
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
public int Quantity { get; set; }
}
此处的PagePartition方法有两个重载方法,其详细功能说明如下:
PagePartition
声明:public PagePiece PagePartition(string RecordSet, string Id, int PageSize, int PageIndex)
用途:分页功能(有主键)
参数:(1)string RecordSet --需要分页的记录集,可以是表、视图、或者SQL语句
(2)string Id --主键
(3)int PageSize --页面大小
(4)int PageIndex --当前页码
返回:PagePiece --页片实体 PagePartition
声明:public PagePiece PagePartition(string RecordSet, int PageSize, int PageIndex)
用途:分页功能(无主键)
参数:(1)string RecordSet -- 需要分页的记录集,可以是表、视图、或者SQL语句
(2)int PageSize --页面大小
(3)int PageIndex --当前页码
返回:PagePiece --页片实体
注意:
(1) 当你需要分页的数据表有“主键”字段时,使用“分页功能(有主键)”。反之,使用“分页功能(无主键)”。
(2) RecordSet是你需要分页的“数据总集”的SQL语句。该SQL语句的形式丰富多样,可以带条件、排序、甚至还能是多表的联合查询、等。
(3) 此方法符合最开始的【第二种】方案,是在SQL Server内部进行的分页操作。而且可以不依赖于排序/排序Id。
本文部分内容参考自公众号:熊泽有话说,在此向号主表达感谢。
原文链接:http://www.developersharp.cc/content8.html
服务条款:http://www.developersharp.cc/buy.html
运行有问题,需要技术支持?请添加微信:894988403
运行有问题,需要技术支持?请添加微信:894988403
1、ROW_NUMBER() OVER()方式(SQL2012以下推荐使用)
示例:
SELECT * FROM
(SELECT ROW_NUMBER() OVER(ORDER BY menuId) AS RowId,* FROM sys_menu ) AS r
WHERE RowId BETWEEN 1 AND 10
用子查询新增一列行号(ROW_NUMBER)RowId查询,比较高效的查询方式,只有在SQL Server2005或更高版本才支持。
BETWEEN 1 AND 10 是指查询第1到第10条数据(闭区间),在这里面需要注意的是OVER的括号里面可以写多个排序字段。
查询结果如下:
通用用法
--pageIndex 表示指定页
--pageSize 表示每页显示的条数
SELECT * FROM
(SELECT ROW_NUMBER() OVER(ORDER BY 排序字段) AS RowId,* FROM 表名 ) AS r
WHERE RowId BETWEEN ((pageIndex-1)*pageSize + 1) AND (pageIndex * PageSize)
2、offset fetch next方式(SQL2012及以上的版本才支持:推荐使用 )
示例:
--offset fetch next方式查询,最高效的查询方式,只有在SQL Server2012或更高版本才支持
SELECT * FROM sys_menu
ORDER BY menuId offset 0 ROWS FETCH NEXT 10 ROWS ONLY
offset 是跳过多少行,
next是取接下来的多少行,
句式 offset...rows fetch nect ..rows only ,注意rows和末尾的only 不要写漏掉了,并且这种方式必须要接着Order by XX 使用,不然会报错。
查询结果如下:
通用用法
--pageIndex 表示指定页
--pageSize 表示每页显示的条数
SELECT * FROM 表名
ORDER BY 排序字段 offset ((pageIndex - 1) * pageSize) ROWS FETCH NEXT pageSize ROWS ONLY
3、top not in方式 (不推荐)
示例:
--查询第11-20条记录
SELECT TOP 10 menuId, *
FROM sys_menu
WHERE menuId NOT IN (SELECT TOP 10 menuId FROM sys_menu)
这条语句的原理是先查询1-10条记录的ID,然后再查询ID不属于这1-10条记录的ID,并且只需要10条记录,因为每页大小就是10,
这就是获取到的第11-20条记录,这是非常简单的一种写法。
另外IN语句与NOT IN语句类似,这是NOT IN的写法,但是这种写法数据量大的话效率太低。
查询结果如下:
通用用法
--pageIndex 表示指定页
--pageSize 表示每页显示的条数
SELECT TOP pageSize menuId, *
FROM sys_menu
WHERE menuId NOT IN (SELECT TOP ((pageSize-1)*pageIndex) menuId FROM sys_menu)
4、通过升序与降序方式进行查询分页(不推荐)
示例:
--使用升序降序的方式分页查询
SELECT * FROM(
SELECT TOP 10 * FROM(
SELECT TOP 20 * FROM sys_menu ORDER BY menuId ASC)
AS TEMP1 ORDER BY menuId DESC)
AS TEMP2 ORDER BY menuId ASC
这条语句首先查询前20条记录,然后在倒序查询前10条记录(即倒数10条记录),
这个时候就已经获取到了11-20条记录,但是他们的顺序是倒序,所以最后又进行升序排序。
查询结果如下:
通用方法
--pageIndex 表示指定页
--pageSize 表示每页显示的条数
SELECT * FROM(
SELECT TOP pageSize * FROM(
SELECT TOP ((pageIndex - 1) * pageSize +(pageSize*2)) * FROM sys_menu ORDER BY menuId ASC)
AS TEMP1 ORDER BY menuId DESC)
AS TEMP2 ORDER BY menuId ASC
5、采用MAX(ID)或者MIN(ID)函数(不推荐)
示例:
--MIN()函数和MAX()函数的使用
--id > 第(PageIndex-1)*PageSize条记录的id AND id <= 第PageIndex*PageSize条记录的id
SELECT TOP 10 * FROM sys_menu WHERE menuId>
(SELECT MAX(menuId) FROM(SELECT TOP 10 menuId FROM sys_menu ORDER BY menuId) AS TEMP1) --(第10条的id)
这个理解起来也简单,先把第10条记录的id找出来(当然这里面是直接使用MAX()进行查找,MIN()函数的用法也是类似的),
然后再对比取比第10条记录的id大的前10条记录即为我们需要的结果。
这里要注意开始时的边界值调整。
查询结果如下:
通用用法
--pageIndex 表示指定页
--pageSize 表示每页显示的条数
SELECT TOP pageSize * FROM sys_menu WHERE menuId>
(SELECT MAX(menuId) FROM(SELECT TOP ((PageIndex-1)*PageSize) menuId FROM sys_menu ORDER BY menuId) AS TEMP1) --(第10条的id)
6、Lambda表达式分页(推荐使用)
我们在数据库分页的时候,还可以在代码里面使用lambda表达式分页。
示例:
List<int> list = new List<int>();
for (int i = 0; i < 100; i++)
{
list.Add(i);
}
//从第11条数据开始,获取10条数据
list = list.Skip(11).Take(10).ToList(); //返回值 11,12,13,14,15,16,17,18,19,20
Skip: 表示从第 (pageIndex * pageSize + 1) 条数据开始,也就是说再这之前有pageIndex * pageSize条数据。
Task:表示获取多少条数据。
通用用法
list = list.Skip(pageIndex * pageSize +1 ).Take(pageSize).ToList();
以上就是数据查询中经常用到的方式,
在数据库版本支持的情况下个人推荐程度排序:offset fetch netct > lambda > ROW_NUMBER() OVER() ,后面的就不推荐使用 。
这样就可以配合存储过程进行分页了。
SQL Server下7种“数据分页”方案,全网最全的更多相关文章
- SQL SERVER数据库三种数据插入方式
数据插入:INSERT INTO A(CBM,CMC) VALUES('1','测试')--单条数据插入INSERT INTO A(CBM,CMC)SELECT '1','测试'--单条数据插入INS ...
- 恢复SQL Server被误删除的数据(再扩展)
恢复SQL Server被误删除的数据(再扩展) 大家对本人之前的文章<恢复SQL Server被误删除的数据> 反应非常热烈,但是文章里的存储过程不能实现对备份出来的日志备份里所删数据的 ...
- 恢复SQL Server被误删除的数据
恢复SQL Server被误删除的数据 <恢复SQL Server被误删除的数据(再扩展)> 地址:http://www.cnblogs.com/lyhabc/p/4620764.html ...
- Sql Server 存储过程中查询数据无法使用 Union(All)
原文:Sql Server 存储过程中查询数据无法使用 Union(All) 微软Sql Server数据库中,书写存储过程时,关于查询数据,无法使用Union(All)关联多个查询. 1.先看一段正 ...
- MS SQL Server数据库修复/MDF数据文件数据恢复/MDF质疑/mdf无法附加
微软的SQL Server 数据库最常用的有两种类型的文件: 1.主要数据文件,文件后缀一般是.MDF: 2.事务日志文件,文件后缀一般是.LDF. 用户数据表.视图.存储过程等等数据,都是存放在MD ...
- 转:Sql Server中清空所有数据表中的记录
如果要删除数据表中所有数据只要遍历一下数据库再删除就可以了,清除所有数据我们可以使用搜索出所有表名,构造为一条SQL语句进行清除了,这里我一一给各位同学介绍. 使用sql删除数据库中所有表是不难的 ...
- Sql Server中清空所有数据表中的记录
Sql Server中清空所有数据表中的记录 清空所有数据表中的记录: 代码如下:exec sp_msforeachtable @Command1 ='truncate table ?'删除所有数据 ...
- [转]实战 SQL Server 2008 数据库误删除数据的恢复
实战 SQL Server 2008 数据库误删除数据的恢复 关键字:SQL Server 2008, recover deleted records 今天有个朋友很着急地打电话给我,他用delete ...
- SQL Server 2008 数据库误删除数据的恢复
原文:SQL Server 2008 数据库误删除数据的恢复 原文:http://www.cnblogs.com/dudu/archive/2011/10/15/sql_server_recover_ ...
- sql点滴38—SQL Server 2008和SQL Server 2008 R2导出数据的选项略有不同
原文:sql点滴38—SQL Server 2008和SQL Server 2008 R2导出数据的选项略有不同 说明: 以前要将一个表中的数据导出为脚本,只有用存储过程.现在在SQL Server ...
随机推荐
- FastJson序列化对象复杂时出错问题解决
FastJson序列化对象复杂时出错问题解决 针对复杂的对象,如Map<String, List<Map<String, XxxObject<A, B, C>>&g ...
- RAID5 IO处理之重构代码详解
1 作用 当阵列降级时,可以添加一块新盘进行重构,以恢复阵列的冗余. 2 发起重构 可以通过以下命令md并发起重构: mdadm -C /dev/md0 --force --run -l 5 -n 3 ...
- Scanner的用法 从键盘输入
先导入包 import java.util.Scanner; 后输入 Scanner Sc=new Scanner(System.in); //(Sc可以自定义,无实质意义) int i; i=Sc. ...
- 5.RabbitMQ系列之headers交换器
headers exchange是根据消息header值而不是routing key将消息路由到队列的交换器. 生产者在消息头中以键值对的形式添加一些值,并将其发送到headers exchange, ...
- 怎么在线预览.doc,.docx,.ofd,.pdf,.wps,.cad文件以及Office文档的在线解析方式。
前言 Office文件在线预览是目前移动化办公的一种新趋势.Office在线预览指的是Office系列的文件在线查看而不依附域客户端的存在.在浏览器或者浏览器控件中可以预览查看Word.PDF.Exc ...
- 在vue中_this和this的区别
_this只是一个变量名,this代表父函数,如果在子函数还用this,this的指 向就变成子函数了,_this就是用来存储指向的 普通函数中的this表示调用此函数时的对象,箭头函数里面的this ...
- (数据科学学习手札145)在Python中利用yarl轻松操作url
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 大家好我是费老师,在诸如网络爬虫.web应用开发 ...
- spalsh安装及简单使用
selenium是浏览器测试自动化工具,很容易完成鼠标点击,翻页等动作,确定是一次只能加载一个页面,无法异步渲染页面,也就限制了selenium爬虫的抓取效率. splash可以实现异步渲染页面,可以 ...
- 为什么 softmax 计算时要先减去最大值
根据 softmax 最基本的定义,计算公式如下所示: $$S_i=\frac{e^{x_i}}{\sum_j e^{x_j}}$$ 原理也很简单,将原向量变为分布的形式(和为1). 看似很美好,但是 ...
- CSS动画-transition/animation
HTML系列: 人人都懂的HTML基础知识-HTML教程(1) HTML元素大全(1) HTML元素大全(2)-表单 CSS系列: CSS基础知识筑基 常用CSS样式属性 CSS选择器大全48式 CS ...