分页功能
本文档详细介绍 cDataBase 类的分页查询功能,支持 SQL Server、MySQL、Access 等数据库。
? 目录
分页概述
什么是分页
分页是将大量数据分成多个页面显示的技术,每页显示固定数量的记录。
分页的优势
- 性能优化 - 只查询需要的数据,减少内存占用
- 用户体验 - 快速加载,避免长时间等待
- 资源节约 - 减少网络传输和数据库负载
分页原理
cDataBase 的分页功能使用 ADO 原生分页属性(Rs.PageSize 和 Rs.AbsolutePage)实现,不修改 SQL 语句。这意味着:
- 分页对所有数据库类型(SQL Server、MySQL、Access、CSV)均有效
- 无需针对不同数据库编写不同的分页 SQL
- 需要使用支持
AbsolutePage的游标类型(如adOpenKeyset)
总记录数: 1000
每页显示: 10
总页数: 100
第 1 页: Rs.AbsolutePage = 1, Rs.PageSize = 10
第 2 页: Rs.AbsolutePage = 2, Rs.PageSize = 10
第 3 页: Rs.AbsolutePage = 3, Rs.PageSize = 10
...Page 方法
语法
vb
Function Page(Optional num As Long = 1, Optional Limit As Long = 10) As cDataBase参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
num | Long | 页码(可选,默认 1) |
Limit | Long | 每页记录数(可选,默认 10) |
返回值
返回 cDataBase 对象,支持链式调用。
示例
vb
' 查询第 1 页,每页 10 条
db.Sql("SELECT * FROM users").Page(1, 10).Query
' 查询第 2 页,每页 20 条
db.Sql("SELECT * FROM users").Page(2, 20).Query支持的数据库
分页使用 ADO 原生分页属性实现,所有数据库类型通用,无需针对不同数据库编写不同的 SQL。
实现原理
Page 方法设置分页参数后,Query 或 Fetch 方法在打开 Recordset 后自动应用:
vb
' 内部实现(源码)
Rs.Open pvRawSqlString, Conn, CurType, LockType, Options
If IsPage Then
Rs.PageSize = pvPageLimit ' 设置每页记录数
Rs.AbsolutePage = pvPageNum ' 设置当前页码
IsPage = False
End If注意事项
- 游标类型要求:分页需要使用支持
AbsolutePage的游标类型(默认adOpenKeyset即可支持) - 不建议使用
adOpenForwardOnly:仅向前游标不支持AbsolutePage,分页将无法正常工作 - SQL 语句不变:分页不会修改原始 SQL,SQL 保持原样执行,分页由 ADO 在 Recordset 层面处理
使用示例
示例 1:基本分页
vb
' 查询第 1 页,每页 10 条
If db.Sql("SELECT * FROM users").Page(1, 10).Fetch Then
Dim i As Long
For i = 1 To db.Rows.Count
Debug.Print db.Rows(i)("name")
Next
End If示例 2:带排序的分页
vb
' 按年龄降序排列,分页显示
If db.Sql("SELECT * FROM users ORDER BY age DESC").Page(2, 10).Fetch Then
Dim i As Long
For i = 1 To db.Rows.Count
Debug.Print db.Rows(i)("name") & " - " & db.Rows(i)("age")
Next
End If示例 3:条件查询分页
vb
' 查询年龄大于 18 的用户,分页显示
If db.Sql("SELECT * FROM users WHERE age > 18").Page(1, 20).Fetch Then
Dim i As Long
For i = 1 To db.Rows.Count
Debug.Print db.Rows(i)("name")
Next
End If示例 4:获取总记录数
vb
' 查询总数
Dim lTotal As Long
lTotal = db.Count("users")
' 计算总页数
Dim lPageSize As Long
lPageSize = 10
Dim lTotalPages As Long
lTotalPages = Int((lTotal + lPageSize - 1) / lPageSize)
' 分页查询
If db.Sql("SELECT * FROM users").Page(1, lPageSize).Fetch Then
' 显示数据
End If示例 5:完整分页函数
vb
' 分页查询函数
Function GetUsersPage(lPage As Long, lPageSize As Long) As Collection
Set GetUsersPage = New Collection
' 查询数据
If db.Sql("SELECT * FROM users ORDER BY id").Page(lPage, lPageSize).Fetch Then
Set GetUsersPage = db.Rows
End If
End Function
' 使用
Dim colUsers As Collection
Set colUsers = GetUsersPage(1, 10)示例 6:分页导航
vb
' 分页导航类
Private m_lCurrentPage As Long
Private m_lPageSize As Long
Private m_lTotalRecords As Long
Private Sub LoadPage(lPage As Long)
' 验证页码
If lPage < 1 Then lPage = 1
Dim lTotalPages As Long
lTotalPages = Int((m_lTotalRecords + m_lPageSize - 1) / m_lPageSize)
If lPage > lTotalPages Then lPage = lTotalPages
m_lCurrentPage = lPage
' 查询数据
If db.Sql("SELECT * FROM users ORDER BY id").Page(lPage, m_lPageSize).Fetch Then
' 显示数据
DisplayUsers
End If
End Sub
Private Sub cmdNextPage_Click()
LoadPage m_lCurrentPage + 1
End Sub
Private Sub cmdPrevPage_Click()
LoadPage m_lCurrentPage - 1
End Sub性能优化
1. 使用索引字段排序
vb
' ? 推荐:使用索引字段排序
db.Sql("SELECT * FROM users ORDER BY id").Page(1, 10).Query
' ? 不推荐:使用非索引字段排序
db.Sql("SELECT * FROM users ORDER BY name").Page(1, 10).Query2. 只查询需要的字段
vb
' ? 推荐:只查询需要的字段
db.Sql("SELECT id, name FROM users").Page(1, 10).Query
' ? 不推荐:查询所有字段
db.Sql("SELECT * FROM users").Page(1, 10).Query3. 使用 WHERE 条件限制
vb
' ? 推荐:使用 WHERE 条件
db.Sql("SELECT * FROM users WHERE status = 'active'").Page(1, 10).Query
' ? 不推荐:查询所有数据再分页
db.Sql("SELECT * FROM users").Page(1, 10).Query4. 合理设置每页记录数
vb
' ? 推荐:合理的每页记录数(10-50)
db.Sql("SELECT * FROM users").Page(1, 20).Query
' ? 不推荐:每页记录数过大
db.Sql("SELECT * FROM users").Page(1, 1000).Query常见问题
Q1: 分页后 RecordCount 返回 -1
原因: 使用了 adOpenForwardOnly 游标类型,不支持 RecordCount 和 AbsolutePage。
解决:
- 使用
adOpenKeyset或adOpenStatic游标类型(默认即是adOpenKeyset) - 分页查询不建议使用
adOpenForwardOnly
Q2: 分页时 AbsolutePage 设置失败
原因: 游标类型不支持 AbsolutePage 属性。
解决:
- 确保使用
adOpenKeyset(默认)或adOpenStatic游标类型 - 检查 SQL 语句是否正确执行并返回结果
Q3: 如何获取总记录数?
vb
' 方法 1:使用 Count 方法
Dim lTotal As Long
lTotal = db.Count("users")
' 方法 2:使用 COUNT(*) 查询
If db.Sql("SELECT COUNT(*) AS cnt FROM users").Fetch Then
lTotal = db.Row("cnt")
End IfQ4: 分页后如何保持排序?
vb
' ? 正确:在 SQL 中包含 ORDER BY
db.Sql("SELECT * FROM users ORDER BY age DESC").Page(1, 10).Query
' ? 错误:分页后再排序(会丢失排序)
db.Sql("SELECT * FROM users").Page(1, 10).Query
' 然后对结果排序(只对当前页排序,不是全局排序)Q5: 如何实现跳转到指定页?
vb
Function GoToPage(lPage As Long, lPageSize As Long) As Boolean
' 验证页码
If lPage < 1 Then lPage = 1
' 查询指定页
If db.Sql("SELECT * FROM users ORDER BY id").Page(lPage, lPageSize).Fetch Then
GoToPage = True
Else
GoToPage = False
End If
End Function最佳实践
1. 始终使用 ORDER BY
vb
' ? 推荐:使用 ORDER BY 保证顺序
db.Sql("SELECT * FROM users ORDER BY id").Page(1, 10).Query
' ? 不推荐:不使用 ORDER BY(顺序不确定)
db.Sql("SELECT * FROM users").Page(1, 10).Query2. 验证页码和每页记录数
vb
' ? 推荐:验证参数
Function GetPage(lPage As Long, lPageSize As Long) As Collection
If lPage < 1 Then lPage = 1
If lPageSize < 1 Then lPageSize = 10
If lPageSize > 100 Then lPageSize = 100 ' 限制最大每页记录数
If db.Sql("SELECT * FROM users ORDER BY id").Page(lPage, lPageSize).Fetch Then
Set GetPage = db.Rows
End If
End Function3. 缓存总记录数
vb
' ? 推荐:缓存总记录数,避免频繁查询
Private m_lCachedTotal As Long
Private m_dtCacheTime As Date
Function GetTotalRecords() As Long
' 缓存 5 分钟
If DateDiff("s", m_dtCacheTime, Now) > 300 Or m_lCachedTotal = 0 Then
m_lCachedTotal = db.Count("users")
m_dtCacheTime = Now
End If
GetTotalRecords = m_lCachedTotal
End Function最后更新: 2026-01-21