海东的技术资料
博客园
::
首页
:: ::
联系
::
订阅
::
管理
::
205 随笔 :: 22 文章 :: 684 评论 :: 68 引用
分页存储过程
/**/
/**/
/**/
/*
说明:1.支持多表查询 2.支持任意排序 3.不支持表别名
参考了
evafly920:[分享]千万数量级分页存储过程(效果演示)
地址:http://blog.csdn.net/evafly920/archive/2006/03/03/614813.aspx
IF(EXISTS(SELECT * FROM sysobjects WHERE [id]=OBJECT_ID('usp_PagingLarge') AND xtype='P'))
DROP PROCEDURE usp_PagingLarge
*/
GO
CREATE
PROCEDURE
usp_PagingLarge
@TableNames
VARCHAR
(
200
),
--
表名,可以是多个表,但不能用别名
@PrimaryKey
VARCHAR
(
100
),
--
主键,可以为空,但@Order为空时该值不能为空
@Fields
VARCHAR
(
200
),
--
要取出的字段,可以是多个表的字段,可以为空,为空表示select *
@PageSize
INT
,
--
每页记录数
@CurrentPage
INT
,
--
当前页,0表示第1页
@Filter
VARCHAR
(
200
)
=
''
,
--
条件,可以为空,不用填 where
@Group
VARCHAR
(
200
)
=
''
,
--
分组依据,可以为空,不用填 group by
@Order
VARCHAR
(
200
)
=
''
--
排序,可以为空,为空默认按主键升序排列,不用填 order by
AS
BEGIN
DECLARE
@SortColumn
VARCHAR
(
200
)
DECLARE
@Operator
CHAR
(
2
)
DECLARE
@SortTable
VARCHAR
(
200
)
DECLARE
@SortName
VARCHAR
(
200
)
IF
@Fields
=
''
SET
@Fields
=
'
*
'
IF
@Filter
=
''
SET
@Filter
=
'
WHERE 1=1
'
ELSE
SET
@Filter
=
'
WHERE
'
+
@Filter
IF
@Group
<>
''
SET
@Group
=
'
GROUP BY
'
+
@Group
IF
@Order
<>
''
BEGIN
DECLARE
@pos1
INT
,
@pos2
INT
SET
@Order
=
REPLACE
(
REPLACE
(
@Order
,
'
asc
'
,
'
ASC
'
),
'
desc
'
,
'
DESC
'
)
IF
CHARINDEX
(
'
DESC
'
,
@Order
)
>
0
IF
CHARINDEX
(
'
ASC
'
,
@Order
)
>
0
BEGIN
IF
CHARINDEX
(
'
DESC
'
,
@Order
)
<
CHARINDEX
(
'
ASC
'
,
@Order
)
SET
@Operator
=
'
<=
'
ELSE
SET
@Operator
=
'
>=
'
END
ELSE
SET
@Operator
=
'
<=
'
ELSE
SET
@Operator
=
'
>=
'
SET
@SortColumn
=
REPLACE
(
REPLACE
(
REPLACE
(
@Order
,
'
ASC
'
,
''
),
'
DESC
'
,
''
),
'
'
,
''
)
SET
@pos1
=
CHARINDEX
(
'
,
'
,
@SortColumn
)
IF
@pos1
>
0
SET
@SortColumn
=
SUBSTRING
(
@SortColumn
,
1
,
@pos1
-
1
)
SET
@pos2
=
CHARINDEX
(
'
.
'
,
@SortColumn
)
IF
@pos2
>
0
BEGIN
SET
@SortTable
=
SUBSTRING
(
@SortColumn
,
1
,
@pos2
-
1
)
IF
@pos1
>
0
SET
@SortName
=
SUBSTRING
(
@SortColumn
,
@pos2
+
1
,
@pos1
-
@pos2
-
1
)
ELSE
SET
@SortName
=
SUBSTRING
(
@SortColumn
,
@pos2
+
1
,
LEN
(
@SortColumn
)
-
@pos2
)
END
ELSE
BEGIN
SET
@SortTable
=
@TableNames
SET
@SortName
=
@SortColumn
END
END
ELSE
BEGIN
SET
@SortColumn
=
@PrimaryKey
SET
@SortTable
=
@TableNames
SET
@SortName
=
@SortColumn
SET
@Order
=
@SortColumn
SET
@Operator
=
'
>=
'
END
DECLARE
@type
varchar
(
50
)
DECLARE
@prec
int
SELECT
@type
=
t.name,
@prec
=
c.prec
FROM
sysobjects o
JOIN
syscolumns c
on
o.id
=
c.id
JOIN
systypes t
on
c.xusertype
=
t.xusertype
WHERE
o.name
=
@SortTable
AND
c.name
=
@SortName
IF
CHARINDEX
(
'
char
'
,
@type
)
>
0
SET
@type
=
@type
+
'
(
'
+
CAST
(
@prec
AS
varchar
)
+
'
)
'
DECLARE
@TopRows
INT
SET
@TopRows
=
@PageSize
*
@CurrentPage
+
1
print
@TopRows
print
@Operator
EXEC
(
'
DECLARE @SortColumnBegin
'
+
@type
+
'
SET ROWCOUNT
'
+
@TopRows
+
'
SELECT @SortColumnBegin=
'
+
@SortColumn
+
'
FROM
'
+
@TableNames
+
'
'
+
@Filter
+
'
'
+
@Group
+
'
ORDER BY
'
+
@Order
+
'
SET ROWCOUNT
'
+
@PageSize
+
'
SELECT
'
+
@Fields
+
'
FROM
'
+
@TableNames
+
'
'
+
@Filter
+
'
AND
'
+
@SortColumn
+
''
+
@Operator
+
'
@SortColumnBegin
'
+
@Group
+
'
ORDER BY
'
+
@Order
+
'
'
)
END
GO
--
调用例子:
--
1.单表/单排序
EXEC
usp_PagingLarge
'
bigtable
'
,
'
d_id
'
,
'
d_id,d_title,d_content,d_time
'
,
20
,
1
,
''
,
''
,
'
d_id desc
'
--
2.单表/多排序
EXEC
usp_PagingLarge
'
bigtable
'
,
'
d_id
'
,
'
*
'
,
20
,
0
,
''
,
''
,
'
d_time asc,d_id desc
'
--
3.多表/单排序
EXEC
usp_PagingLarge
'
bigtable left join bigtable_author on bigtable.d_id=bigtable_author.BigTable_id
'
,
'
bigtable.d_id
'
,
'
bigtable.d_id,bigtable.d_title,bigtable.d_content,bigtable.d_time,bigtable_author.d_author
'
,
20
,
0
,
''
,
''
,
'
bigtable.d_id asc
'
--
4.多表/多排序
EXEC
usp_PagingLarge
'
bigtable left join bigtable_author on bigtable.d_id=bigtable_author.BigTable_id
'
,
'
bigtable.d_id
'
,
'
bigtable.d_id,bigtable.d_title,bigtable.d_content,bigtable.d_time,bigtable_author.d_author
'
,
20
,
0
,
''
,
''
,
'
bigtable.d_time asc,bigtable.d_id desc
'
与自定义分页结合例子:
/Files/jiny-z/Paging_Custom.rar
alter
PROCEDURE
SP_Pagination
/**/
/*
***************************************************************
** 分页存储过程 **
***************************************************************
参数说明:
1.Tables :表名称,视图
2.PrimaryKey :主关键字
3.Sort :排序语句,不带Order By 比如:NewsID Desc,OrderRows Asc
4.CurrentPage :当前页码
5.PageSize :分页尺寸
6.Fields:字段
6.Filter :过滤语句,不带Where
7.Group :Group语句,不带Group By
8.docount: 1返回总行数,0返回列表
**************************************************************
*/
(
@Tables
varchar
(
1000
),
@PrimaryKey
varchar
(
100
),
@Sort
varchar
(
200
)
=
NULL
,
@CurrentPage
int
=
1
,
@PageSize
int
=
10
,
@Fields
varchar
(
1000
)
=
'
*
'
,
@Filter
varchar
(
1000
)
=
NULL
,
@Group
varchar
(
1000
)
=
NULL
,
@docount
bit
=
0
)
AS
/**/
/*
默认排序
*/
IF
@Sort
IS
NULL
OR
@Sort
=
''
SET
@Sort
=
@PrimaryKey
DECLARE
@SortTable
varchar
(
100
)
DECLARE
@SortName
varchar
(
100
)
DECLARE
@strSortColumn
varchar
(
200
)
DECLARE
@operator
char
(
2
)
DECLARE
@type
varchar
(
100
)
DECLARE
@prec
int
/**/
/*
设定排序语句.
*/
IF
CHARINDEX
(
'
DESC
'
,
@Sort
)
>
0
BEGIN
SET
@strSortColumn
=
REPLACE
(
@Sort
,
'
DESC
'
,
''
)
SET
@operator
=
'
<=
'
END
ELSE
BEGIN
IF
CHARINDEX
(
'
ASC
'
,
@Sort
)
=
0
SET
@strSortColumn
=
REPLACE
(
@Sort
,
'
ASC
'
,
''
)
SET
@operator
=
'
>=
'
END
IF
CHARINDEX
(
'
.
'
,
@strSortColumn
)
>
0
BEGIN
SET
@SortTable
=
SUBSTRING
(
@strSortColumn
,
0
,
CHARINDEX
(
'
.
'
,
@strSortColumn
))
SET
@SortName
=
SUBSTRING
(
@strSortColumn
,
CHARINDEX
(
'
.
'
,
@strSortColumn
)
+
1
,
LEN
(
@strSortColumn
))
END
ELSE
BEGIN
SET
@SortTable
=
@Tables
SET
@SortName
=
@strSortColumn
END
SELECT
@type
=
t.name,
@prec
=
c.prec
FROM
sysobjects o
JOIN
syscolumns c
on
o.id
=
c.id
JOIN
systypes t
on
c.xusertype
=
t.xusertype
WHERE
o.name
=
@SortTable
AND
c.name
=
@SortName
IF
CHARINDEX
(
'
char
'
,
@type
)
>
0
SET
@type
=
@type
+
'
(
'
+
CAST
(
@prec
AS
varchar
)
+
'
)
'
DECLARE
@strPageSize
varchar
(
50
)
DECLARE
@strStartRow
varchar
(
50
)
DECLARE
@strFilter
varchar
(
200
)
DECLARE
@strSimpleFilter
varchar
(
200
)
DECLARE
@strGroup
varchar
(
200
)
/**/
/*
默认当前页
*/
IF
@CurrentPage
<
1
SET
@CurrentPage
=
1
/**/
/*
设置分页参数.
*/
SET
@strPageSize
=
CAST
(
@PageSize
AS
varchar
(
50
))
SET
@strStartRow
=
CAST
(((
@CurrentPage
-
1
)
*
@PageSize
+
1
)
AS
varchar
(
50
))
/**/
/*
筛选以及分组语句.
*/
IF
@Filter
IS
NOT
NULL
AND
@Filter
!=
''
BEGIN
SET
@strFilter
=
'
WHERE
'
+
@Filter
+
'
'
SET
@strSimpleFilter
=
'
AND
'
+
@Filter
+
'
'
END
ELSE
BEGIN
SET
@strSimpleFilter
=
''
SET
@strFilter
=
''
END
IF
@Group
IS
NOT
NULL
AND
@Group
!=
''
SET
@strGroup
=
'
GROUP BY
'
+
@Group
+
'
'
ELSE
SET
@strGroup
=
''
declare
@cTemp
NVarChar
(
1000
)
declare
@PageCount
int
,
@lineCount
decimal
CREATE
TABLE
#
temp
(linecount
INT
)
set
@cTemp
=
'
insert into #temp (linecount) select count(*) FROM
'
+
@Tables
+
@strFilter
+
'
'
+
@strGroup
exec
(
@cTemp
)
select
@lineCount
=
linecount
from
#
temp
drop
table
#
temp
if
(
@docount
=
1
)
begin
select
@lineCount
'
总行数
'
end
else
begin
--
得到总页数
set
@PageCount
=
CEILING
(
@lineCount
/
@strPageSize
)
if
@CurrentPage
>
@PageCount
begin
set
@cTemp
=
'
SELECT
'
+
@Fields
+
'
FROM
'
+
@Tables
+
'
WHERE 1>2
'
end
else
begin
/**/
/*
执行查询语句
*/
set
@cTemp
=
'
DECLARE @SortColumn
'
+
@type
+
'
SET ROWCOUNT
'
+
@strStartRow
+
'
SELECT @SortColumn=
'
+
@strSortColumn
+
'
FROM
'
+
@Tables
+
@strFilter
+
'
'
+
@strGroup
+
'
ORDER BY
'
+
@Sort
+
'
SET ROWCOUNT
'
+
@strPageSize
+
'
SELECT
'
+
@Fields
+
'
FROM
'
+
@Tables
+
'
WHERE
'
+
@strSortColumn
+
@operator
+
'
@SortColumn
'
+
@strSimpleFilter
+
'
'
+
@strGroup
+
'
ORDER BY
'
+
@Sort
+
''
end
--
print @cTemp
EXEC
(
@cTemp
)
end
--
---------------------------------------------------
分页查询的方法已经很多很多,在这里我也加入成为其中一员。
SQL Server中有一个Set Rowcount的的设置,它的意思是使命令的处理在响应指定的行数之后停止处理命令,利用这个特点,我们可以借用它来在一个千万行级数据表中实现高性能分页查询。先来说说实现方式:
1
、我们来假定Table中有一个已经建立了索引的主键字段ID(整数型),我们将按照这个字段来取数据进行分页。
2
、页的大小我们放在
@PageSize中
3
、当前页号我们放在
@CurrentPage中
4
、如何让记录指针快速滚动到我们要取的数据开头的那一行呢,这是关键所在!有了Set
RowCount
,我们就很容易实现了。
5
、如果我们成功地滚动记录指针到我们要取的数据的开头的那一行,然后我们把那一行的记录的ID字段的值记录下来,那么,利用Top和条件,我们就很容易的得到指定页的数据了。当然,有了Set
RowCount
,我们难道还用Top么?
看看Set Rowcount怎么来帮我们的忙吧:
Declare
@ID
int
Declare
@MoveRecords
int
--
@CurrentPage和@PageSize是传入参数
Set
@MoveRecords
=
@CurrentPage
*
@PageSize
+
1
--
下面两行实现快速滚动到我们要取的数据的行,并把ID记录下来
Set
Rowcount
@MoveRecords
Select
@ID
=
ID
from
Table1
Order
by
ID
Set
Rowcount
@PageSize
--
最恨为了减少麻烦使用*了,但是在这里为了说明方便,暂时用一下
Select
*
From
Table1
Where
ID
>=
@ID
Order
By
ID
Set
Rowcount
0
大家可以试试看,在一个1千W记录的表里面,一下子方翻页到第100页(每页100条),看看有多快!
分享]千万数量级分页存储过程(带效果演示)
效果演示:http:
//
www.cn5135.com
/
_App
/
Opportunities
/
QueryResult.aspx
CREATE
PROCEDURE
CN5135_SP_Pagination
/**/
/*
***************************************************************
** 千万数量级分页存储过程 **
***************************************************************
参数说明:
1.Tables :表名称,视图
2.PrimaryKey :主关键字
3.Sort :排序语句,不带Order By 比如:NewsID Desc,OrderRows Asc
4.CurrentPage :当前页码
5.PageSize :分页尺寸
6.Filter :过滤语句,不带Where
7.Group :Group语句,不带Group By
效果演示:http://www.cn5135.com/_App/Opportunities/QueryResult.aspx
**************************************************************
*/
(
@Tables
varchar
(
1000
),
@PrimaryKey
varchar