昨天遇到了一个问题,就是如何取出SQL Server / Access数据表中中间的部分记录,例如要取出第9条到第16条的“最新”文章记录,仔细考虑了一下得到了一种方法,下面的代码示例都以下面的表结构为准:
| Articles 表 | SQL Server 类型 | Oracle 类型 | |
| PK | Id | int (自增) | number(9) (插入时在当前最大值上加1) |
| Author | nvarchar(10) | nvarchar2(10) | |
| Title | nvarchar(50) | nvarchar2(50) | |
| PubTime | datetime | date |
这种方法是“拼凑” SQL 语句:用两次 TOP 命令取得我们所要的数据,例如:
1
SELECT * FROM
2
(
3
SELECT TOP 8 * FROM
4
(
5
SELECT TOP 16 *
6
FROM Articles
7
ORDER BY PubTime DESC
8
)
9
ORDER BY PubTime ASC
10
)
11
ORDER BY PubTime DESC
2
3
4
5
6
7
8
9
10
11
这个的想法就是“掐头去尾”,要取出按时间降序排列的第9到第16条这8条记录,首先先按时间降序取出前16条记录,由于这16条记录的后8条正是我们需要的记录,所以再对这16条记录按时间升序排列,取出前8条,这8条正是我们需要的记录,但是排序不对,最后再对这8条记录按时间降序排列,正好得到需要的记录和排序方式。
其实,取出中间数据的方法还有很多,这和分页的原理差不多,在网上还发现使用存储过程来实现的,这一种方式是以 ASP.NET Forum 为代表的、“临时表”方法:即在存储过程中建立一个临时表,该临时表包含一个序号字段(1,2,3,....)以及表的主键(其他能够唯一确定一行记录的字段也是可以的)字段。存储过程可能如下:
1
CREATE Procedure GetAllArticles_Paged
2
(
3
@PageIndex int,
4
@PageSize int,
5
@TotalRecords out int,
6
@TotalPages out int
7
)
8
AS
9
10
DECLARE @PageLowerBound int
11
DECLARE @PageUpperBound int
12
13
-- Set the page bounds
14
SET @PageLowerBound = @PageSize * @PageIndex
15
SET @PageUpperBound = @PageLowerBound + @PageSize + 1
16
17
-- Create a temp table to store the select results
18
CREATE TABLE #tmp
19
(
20
RecNo int IDENTITY (1, 1) NOT NULL,
21
ArticleID int
22
)
23
24
INSERT INTO #tmp
25
SELECT [ID]
26
FROM Articles
27
ORDER BY PubTime DESC
28
29
SELECT A.*
30
FROM Articles A (nolock), #tmp T
31
WHERE A.ID = T.ArticleID AND
32
T.RecNo > @PageLowerBound AND
33
T.RecNo < @PageUpperBound
34
ORDER BY T.RecNo
35
36
GO
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
对于 Oracle 数据库,有几处不同严重妨碍了上面几个方法的实施,比如,Oracle 不支持 TOP 关键字:不过这个好像并不十分严重,因为它提供了 rownum 这个隐式游标,可以实现与 TOP 类似的功能,如:
要写成
rownum 是记录序号(1,2,3...),但有一个比较麻烦的事情是:如果 SQL 语句中有 ORDER BY ... 排序的时候,rownum 居然是先“标号”后排序!这样,这个序号如果不加处理是不合乎使用需求的。
至于临时表,Oracle 的临时表和 SQL Server 的有很大不同,
1
SELECT * FROM
2
(
3
SELECT A.*, rownum r
4
FROM
5
(
6
SELECT *
7
FROM Articles
8
ORDER BY PubTime DESC
9
) A
10
WHERE rownum <= PageUpperBound
11
) B
12
WHERE r > PageLowerBound;
2
3
4
5
6
7
8
9
10
11
12