欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

分页存储过程(三)在sqlserver中打造更加准确的分页结果

程序员文章站 2023-12-10 15:58:40
有人提出游标不好,会锁定行,幸亏我锁定的是临时表,不是数据表,不影响数据表的写操作。 下面是14楼的回复,让我茅塞顿开,于是有了今天的改进版,取消了游标的使用,临时表还是存...
有人提出游标不好,会锁定行,幸亏我锁定的是临时表,不是数据表,不影响数据表的写操作。

下面是14楼的回复,让我茅塞顿开,于是有了今天的改进版,取消了游标的使用,临时表还是存在的,谢谢。

其实你只要分成两次查询即可:
1, 还是用row_number查主表分页
2, row_number查主表分页 inner join 明细表..用不到游标的.

复制代码 代码如下:

--不用游标的分页
--先将分页的主表放在临时表中,然后用临时表和子表联合查询,来获取子表信息
--既保证了分页的正确性,也包括了子表信息
create table #order
(
number bigint,
orderseqno varchar(36),
)
insert into #order
select * from (select row_number() over (order by oi.createdate desc) as rownumber,oi.orderseqno
from orderinfo oi where oi.orderseqno like '%2%' ) as o
where o.rownumber between 10 and 20

select * from #order inner join orderdetail od on od.orderseqno=#order.orderseqno

drop table #order


复制代码 代码如下:

--select top 10 oi.orderseqno, oi.goodsname ,ci.companyname,od.*
--from orderinfo oi inner join companyinfo ci on oi.companyid=ci.companyid
--left join orderdetail od on oi.orderseqno=od.orderseqno


--使用row_unmber()实现分页
--本来我们想要的结果是10条订单,结果却不是10条订单,而是10条明细
--其实是针对的子表进行分页了,订单并不是要显示的个数,出来的个数是明细的个数
--就是因为主表和子表联合查询的结果,主表记录和子表记录是1:n的关系,一个主表记录有多个明细

--建立聚集索引
-- clustered index index_orderinfo on orderinfo (orderseqno)
--显示查询执行计划
--set statistics io on

select * from
(select row_number () over (order by oi.createdate desc) as rownumber,oi.orderseqno ,od.orderdetailid
from orderinfo oi left join orderdetail od on oi.orderseqno=od.orderseqno
where oi.orderseqno like '%2%'
) as o
where rownumber between 10 and 20

--不用游标的分页
--先将分页的主表放在临时表中,然后用临时表和子表联合查询,来获取子表信息
--既保证了分页的正确性,也包括了子表信息
create table #order
(
number bigint,
orderseqno varchar(36),
)
insert into #order
select * from (select row_number() over (order by oi.createdate desc) as rownumber,oi.orderseqno
from orderinfo oi where oi.orderseqno like '%2%' ) as o
where o.rownumber between 10 and 20

select * from #order inner join orderdetail od on od.orderseqno=#order.orderseqno

drop table #order
--解决上面的问题,有以下几种办法
--1、先根据条件查询主表记录,然后在c#代码中循环,再次到数据库查询每条主表记录的明细信息,然后赋值给属性
--2、在数据库的存储过程中使用游标,也是先查询主表记录,然后使用游标循环的过程中,查询子表信息,然后在c#中
--集中处理
--很显然,后一种减少了数据库的往来开销,一次获取了想要的数据,个人认为要比第一种好,欢迎大家一起讨论更好的办法

--需要注意的就是row_number()返回的类型是bigint,而不是int
--下面是游标的存储过程


--建立主表临时表
create table #temp
(
rownumber bigint,
orderseqno varchar(36),
goodsname varchar(50),
companyname varchar(100)
)
--建立子表临时表
create table #detail
(
orderseqno varchar(36),
detailid uniqueidentifier,
unitprice decimal(12,2),
qty int
)
--插入主表数据到主表临时表

insert into #temp
select *
--oo.rownumber, oo.orderseqno, oo.goodsname, oo.companyname
from
(select row_number () over (order by oi.createdate desc) as rownumber,
oi.orderseqno, oi.goodsname ,ci.companyname
from orderinfo oi inner join companyinfo ci on oi.companyid=ci.companyid
where oi.createdate<getdate()
) as oo
where rownumber between 10 and 20

--定义游标
declare @temp_cursor cursor
--给游标赋值
set @temp_cursor=cursor for select #temp.orderseqno,#temp.goodsname from #temp

--定义游标循环过程中所需保存的临时数据
declare @orderseqno varchar(36),@goodsname varchar(50)

--打开游标
open @temp_cursor

fetch next from @temp_cursor into @orderseqno,@goodsname
--循环游标,查询子表数据,然后插入子表临时表
while @@fetch_status=0
begin
insert into #detail
select od.orderseqno,od.orderdetailid, od.unitprice,od.qty
from orderdetail od
where od.orderseqno=@orderseqno

fetch next from @temp_cursor into @orderseqno,@goodsname
end

--关闭游标
close @temp_cursor
deallocate @temp_cursor

select * from #temp
select * from #detail
--删除临时表
drop table #temp
drop table #detail