实现分页查询的一种方法,使用Microsoft SQL Server数据库

实现分页查询的一种方法,使用Microsoft SQL Server数据库

各数据库均提供了分页查询的语句和相应的方法,但是如果查询的结果较为复杂,如查询结果需要结过再计算、分段、添加汇总行等操作后再输出,就需要考虑的更为全面一些,而且还要配合前端实现的逻辑。本文是在实践中用到一种方法,仅供参考。

一、SQL语言用于分页的语句

在最新版本的Microsoft SQL Server中,分页查询通常是通过使用OFFSETFETCH NEXT子句来实现的。这种方法是在SQL Server 2012及以后的版本中引入的,它提供了一种更直观和高效的方式来进行分页。

以下是一个使用OFFSETFETCH NEXT进行分页查询的基本示例:

sql 复制代码
SELECT *
FROM YourTable
ORDER BY SomeColumn
OFFSET (@pageIndex - 1) * @pageSize ROWS
FETCH NEXT @pageSize ROWS ONLY;

在这个例子中:

  • @pageIndex 表示当前页码,它是一个变量,代表用户请求的页码。
  • @pageSize 表示每页显示的记录数,它也是一个变量。
  • OFFSET 用于跳过指定数量的行,计算方式是(当前页码 - 1) * 每页记录数
  • FETCH NEXT 用于限制结果集只返回接下来的指定数量的行,即每页的记录数。
    这种方法的优点是它简单、直观,并且性能良好,特别是在处理大量数据时。它避免了在旧版本中常用的一些复杂方法,如使用ROW_NUMBER()函数或者多次查询来确定行的偏移量。
    请注意,为了使用这种方法,你需要确保你的SQL Server版本至少是2012或更高版本。如果你使用的是更早的版本,你可能需要使用其他方法,如ROW_NUMBER()或者CURSOR等。

二、后端过程设计示例

sql 复制代码
USE [hyX1201]
GO
/****** Object:  StoredProcedure [dbo].[X9_ZZCH_MXZZ]    Script Date: 2024-03-21 15:39:59 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- ==================================================================================
-- Author:		昆山华岳软件有限公司 岳国军
-- Script Date: 2023-11-30
-- Description:	总账查询:存货总账_明细总账 分页查询示例程序,本例不使用存储表
-- ===================================================================================
ALTER PROCEDURE [dbo].[X9_ZZCH_MXZZ]
	(@KSNY CHAR(6),
	@JSNY CHAR(6),
	@CKMC NVARCHAR(50),
	@CXYC INT,@CXHS INT,@RQSJ VARCHAR(30))
	--查询页次:-1 获取总行数,>=0 查询的页次,
	--查询行数:每页查询行数,
	--日期时间:可用于命名临时表,由前端生成
AS
	DECLARE	@LJZD VARCHAR(100);
	SET @LJZD ='存货明细账查询';
	IF @CXYC=-2
		RETURN;
	IF @CXYC=-1
		BEGIN
			--返回结果行数
			WITH MXZZ (CHXH,CHDH,CHMC,XH1,XH2,XH3,GG1,JLDW,QCSL,QCJS,QCJE,SRSL,SRJS,SRJE,FCSL,FCJS,FCJE,JCSL,JCJS,JCJE) AS 
				(SELECT XM.CHXH, XM.CHDH, XM.CHMC, XM.XH1, XM.XH2, XM.XH3, XM.GG1, XM.JLDW,
					SUM(CASE ZZ.NY WHEN @KSNY THEN ZZ.QCSL ELSE 0 END) AS QCSL, 
					SUM(CASE ZZ.NY WHEN @KSNY THEN ZZ.QCJS ELSE 0 END) AS QCJS, 
					SUM(CASE ZZ.NY WHEN @KSNY THEN ZZ.QCJE ELSE 0 END) AS QCJE, 
					SUM(ZZ.SRSL) AS SRSL, SUM(ZZ.SRJS) AS SRJS, SUM(ZZ.SRJE) AS SRJE, SUM(ZZ.FCSL) AS FCSL, 
					SUM(ZZ.FCJS) AS FCJS, SUM(ZZ.FCJE) AS FCJE, 
					SUM(CASE ZZ.NY WHEN @JSNY THEN ZZ.JCSL ELSE 0 END) AS JCSL, 
					SUM(CASE ZZ.NY WHEN @JSNY THEN ZZ.JCJS ELSE 0 END) AS JCJS, 
					SUM(CASE ZZ.NY WHEN @JSNY THEN ZZ.JCJE ELSE 0 END) AS JCJE
				FROM UTZZCH AS ZZ INNER JOIN MLCHXM AS XM ON ZZ.CHXH = XM.CHXH
				WHERE (ZZ.CKMC=@CKMC OR @CKMC='') AND (ZZ.NY BETWEEN @KSNY AND @JSNY)
				GROUP BY XM.CHXH, XM.CHDH, XM.CHMC, XM.XH1, XM.XH2, XM.XH3, XM.GG1, XM.JLDW)
			SELECT COUNT(*) AS CXHS FROM MXZZ ;	
		END
	IF @CXYC>-1
		BEGIN
			--返回当前页所需要查询结果 
			WITH MXZZ (CHXH,CHDH,CHMC,XH1,XH2,XH3,GG1,JLDW,QCSL,QCJS,QCJE,SRSL,SRJS,SRJE,FCSL,FCJS,FCJE,JCSL,JCJS,JCJE) AS 
				(SELECT XM.CHXH, XM.CHDH, XM.CHMC, XM.XH1, XM.XH2, XM.XH3, XM.GG1, XM.JLDW,
					SUM(CASE ZZ.NY WHEN @KSNY THEN ZZ.QCSL ELSE 0 END) AS QCSL, 
					SUM(CASE ZZ.NY WHEN @KSNY THEN ZZ.QCJS ELSE 0 END) AS QCJS, 
					SUM(CASE ZZ.NY WHEN @KSNY THEN ZZ.QCJE ELSE 0 END) AS QCJE, 
					SUM(ZZ.SRSL) AS SRSL, SUM(ZZ.SRJS) AS SRJS, SUM(ZZ.SRJE) AS SRJE, SUM(ZZ.FCSL) AS FCSL, 
					SUM(ZZ.FCJS) AS FCJS, SUM(ZZ.FCJE) AS FCJE, 
					SUM(CASE ZZ.NY WHEN @JSNY THEN ZZ.JCSL ELSE 0 END) AS JCSL, 
					SUM(CASE ZZ.NY WHEN @JSNY THEN ZZ.JCJS ELSE 0 END) AS JCJS, 
					SUM(CASE ZZ.NY WHEN @JSNY THEN ZZ.JCJE ELSE 0 END) AS JCJE
				FROM UTZZCH AS ZZ INNER JOIN MLCHXM AS XM ON ZZ.CHXH = XM.CHXH
				WHERE (ZZ.CKMC=@CKMC OR @CKMC='') AND (ZZ.NY BETWEEN @KSNY AND @JSNY)
				GROUP BY XM.CHXH, XM.CHDH, XM.CHMC, XM.XH1, XM.XH2, XM.XH3, XM.GG1, XM.JLDW)
			SELECT CHXH,CHDH,CHMC,XH1,XH2,XH3,GG1,JLDW,QCSL,QCJS,
				CASE WHEN QCSL<>0 THEN QCJE/QCSL ELSE 0 END AS QCDJ,QCJE,
				SRSL,SRJS,SRJE,FCSL,FCJS,FCJE,JCSL,
				CASE WHEN JCSL>0 THEN JCJE/JCSL ELSE 0 END AS JCDJ,JCJS,JCJE,@LJZD AS 链接功能 FROM MXZZ
			ORDER BY CHDH,CHXH  offset (@CXYC*@CXHS)  rows fetch next @CXHS rows only;	
			RETURN;
		END
RETURN;

三、前端实现逻辑

vbnet 复制代码
  '由前端定义每次查询的行数
  Public pCXHS As Integer = 25		'查询行数,不再存储本地文件
  Dim DqPage As Integer = 0			'当前页
  Dim EndPage As Integer = 0		'最后一页
  Dim CXrqsj As String = ...		'定义一时间戳
  Dim CXsql As String = ""
  dim Dt1 as DataTable
  dim Sql1 as String 				'原来的查询语句。	
  ...... sql1根据前端定义赋值
  EndPage = -1
  If InStr(UCase(Sql1), "<CXYC>") > 0 And InStr(UCase(Sql1), "<CXHS>") > 0 Then
      Dim CRsql As String = Replace(CXsql, "<CXYC>", "-1")
      CRsql = Replace(CRsql, "<CXHS>", pCXHS)
      CRsql = Replace(CRsql, "<RQSJ>", CXrqsj)
      '初次查询时获取总行数
      Dim cxrows As Integer = GetDBInteger(CRsql)
      If cxrows <= 0 Then
          Exit Sub
      End If
      '计算出最大页号
      EndPage = cxrows \ pCXHS
      If (cxrows Mod pCXHS) = 0 Then
          EndPage -= 1
      End If
      L3.Caption = "共[" & cxrows.ToString.Trim & "]行记录,分" & (EndPage + 1).ToString.Trim & "页查询"
  Else
      L3.Caption = ""
  End If
  ......根据前端查询状态确定当前页次后查询相应页次的数据
  Dt1 = New DataTable
  Dim Sql1 As String
  Sql1 = Replace(CXsql, "<CXYC>", DqPage)
  Sql1 = Replace(Sql1, "<CXHS>", pCXHS)
  Sql1 = Replace(Sql1, "<RQSJ>", CXrqsj)
  Dt1 = GetDTread(Sql1)
  If IsNothing(Dt1) Then
      XXshow("数据未能正确载入", Me)
      Exit Sub
  End If
  GridCX.DataSource = Nothing
  GridCX.DataSource = Dt1
  Gdgv.RefreshData()
  '更新翻页按钮状态
  Btpg1.Enabled = (DqPage > 0) And (EndPage > 0)
  Btpg2.Enabled = (DqPage > 0) And (EndPage > 0)
  Btpg3.Enabled = (DqPage < EndPage) And (EndPage > 0)
  Btpg4.Enabled = (DqPage < EndPage) And (EndPage > 0)
  Lczs.Text = " 第 " & (DqPage + 1).ToString.Trim & " 页 共 " & (EndPage + 1).ToString.Trim & " 页 "
  ...... 

总结

如果查询结果行数非常多或需要的计算较为复杂,应在初次查询使用(返回行数)时,将查询结果存在临时表中,后面查询就可以从此查询了。总之,不管什么方法,都是需要前端合理配合,才能收到更好的效果。

相关推荐
毕小宝3 分钟前
H2 Database Console未授权访问漏洞封堵
数据库·h2
Rverdoser6 分钟前
Mongodb地理信息数据查询
数据库·mongodb
chenyang_8811 分钟前
MySQL——statement对象详解
数据库·mysql·oracle
#学习的路上38 分钟前
Bean的管理
java·前端·数据库
a_zhee140 分钟前
[Redis]哨兵机制
数据库·redis·缓存
GodGump41 分钟前
DB-GPT 文档切分报错
数据库·gpt
a未来永远是个未知数1 小时前
数据库重命名脚本
数据库
java6666688881 小时前
Java中的内存数据库与缓存技术
java·数据库·缓存
水题检测鸟1 小时前
ACID及事务隔离级别
数据库
Obsession12341 小时前
MySQL高可用之 MMM结构
数据库·mysql