链式 CURD - 综合示例与最佳实践
本文包含实战示例、与传统 SQL 对比、常见问题和最佳实践。方法详细说明参见各子页面:
综合示例
示例1:用户管理系统
vb
' 查询活跃用户列表(排序+分页)
If db.Table("users") _
.Where("status=?", "active") _
.WhereNotNull("email") _
.OrderByDesc("last_login") _
.Page(1, 20) _
.RowRead Then
Do Until db.Rs.EOF
Debug.Print db.Rs!name & " | " & db.Rs!email
db.Rs.MoveNext
Loop
End If
' 搜索用户(模糊匹配+OR条件)
db.Table("users") _
.WhereLike("name", "%" & keyword & "%") _
.OrWhereLike("email", "%" & keyword & "%") _
.OrderBy("name") _
.RowRead
' 创建新用户
With db.Table("users")
.Field "name", txtName.Text
.Field "age", CLng(txtAge.Text)
.Field "email", txtEmail.Text
.Field "status", "active"
.RowCreate
newId = db.LastInsertId
End With
' 更新用户信息
With db.Table("users").Where("id=?", userId)
.Field "name", txtName.Text
.Field "email", txtEmail.Text
.RowUpdate
End With
' 删除过期用户
db.Table("users").Where("status=?", "expired").WhereNull("email").RowDelete示例2:报表统计
vb
' 部门人数统计
db.Table("users") _
.Columns("dept,COUNT(*) AS cnt") _
.GroupBy("dept") _
.Having("cnt>5") _
.OrderByDesc("cnt") _
.RowRead
' 月度销售汇总
db.Table("orders") _
.Columns("YEAR(created_at) AS y,MONTH(created_at) AS m,SUM(amount) AS total") _
.GroupBy("YEAR(created_at)") _
.GroupBy("MONTH(created_at)") _
.WhereBetween("created_at", "2026-01-01", "2026-12-31") _
.OrderBy("y") _
.OrderBy("m") _
.RowRead
' 快速统计
Dim totalUsers As Long
totalUsers = db.Table("users").RowCount
Dim avgSalary As Variant
avgSalary = db.Table("users").Where("dept=?", "IT").RowAvg("salary")
Dim maxOrder As Variant
maxOrder = db.Table("orders").RowMax("amount")
' 获取所有部门名称列表
Dim depts As Collection
Set depts = db.Table("users").Distinct.Columns("dept").RowPluck("dept")示例3:多表关联查询
vb
' 订单详情(订单+用户+产品)
db.Table("orders") _
.Columns("orders.id,users.name AS user_name,products.title AS product,orders.amount") _
.Join("users", "orders.user_id=users.id") _
.LeftJoin("products", "orders.product_id=products.id") _
.Where("orders.amount>?", 100) _
.WhereBetween("orders.created_at", "2026-01-01", "2026-06-30") _
.OrderByDesc("orders.amount") _
.Limit(50) _
.RowRead示例4:判断存在与提取列表
vb
' 注册前检查邮箱是否已存在
If db.Table("users").Where("email=?", newEmail).RowExists Then
MsgBox "该邮箱已注册"
Exit Sub
End If
' 获取管理员ID列表
Dim adminIds As Collection
Set adminIds = db.Table("users").WhereIn("role", "admin,superadmin").RowPluck("id")
' 批量操作:将所有管理员标记为在线
With db.Table("users").WhereIn("id", "1,2,3,5")
.Field "online_status", True
.RowUpdate
End With与传统 SQL 方式对比
查询对比
vb
' ── 传统 SQL 方式 ──
db.Sql("SELECT id,name FROM users WHERE age > 18 AND dept IN ('IT','HR') ORDER BY age DESC LIMIT 10").Fetch
' ── 链式构建器方式 ──
db.Table("users") _
.Columns("id,name") _
.Where("age>?", 18) _
.WhereIn("dept", "IT,HR") _
.OrderByDesc("age") _
.Limit(10) _
.RowRead插入对比
vb
' ── 传统 SQL 方式 ──
db.Sql("INSERT INTO users (name,age) VALUES ('张三',25)").Exec
' ── 链式构建器方式 ──
db.Table("users").Field("name", "张三").Field("age", 25).RowCreate更新对比
vb
' ── 传统 SQL 方式 ──
db.Sql("UPDATE users SET name='李四' WHERE id=1").Exec
' ── 链式构建器方式 ──
db.Table("users").Where("id=?", 1).Field("name", "李四").RowUpdate删除对比
vb
' ── 传统 SQL 方式 ──
db.Sql("DELETE FROM users WHERE status='expired'").Exec
' ── 链式构建器方式 ──
db.Table("users").Where("status=?", "expired").RowDelete链式优势
| 维度 | 传统 SQL | 链式构建器 |
|---|---|---|
| 可读性 | 长字符串拼接,难以阅读 | 方法链语义清晰 |
| SQL 注入风险 | 手动拼接值,容易遗漏转义 | 参数自动转义 |
| 跨数据库 | 需手写不同数据库的分页/限制语法 | 自动适配 MySQL/MSSQL/Access |
| 维护性 | 改条件需重写整个 SQL | 增删链式方法即可 |
| 调试 | 需打印完整 SQL | 每步对应一个 SQL 子句 |
常见问题
Q1: 链式构建器与 Sql() 方法能混用吗?
不建议混用。链式构建器(Table + Where + ...)和传统方式(Sql)使用不同的内部状态。如果已调用 Sql(),链式条件不会生效;反之亦然。请选择一种方式:
vb
' 方式1:链式构建器(推荐用于标准 CRUD)
db.Table("users").Where("id=?", 1).RowRead
' 方式2:传统 SQL(适合复杂查询、子查询等)
db.Sql("SELECT * FROM users WHERE id = 1").FetchQ2: 复杂查询不适合链式怎么办?
对于子查询、UNION、窗口函数等高级 SQL,链式构建器无法覆盖,请使用传统 Sql() 方式:
vb
' 子查询 - 使用 Sql() 方式
db.Sql("SELECT * FROM users WHERE id IN (SELECT user_id FROM orders WHERE amount > 1000)").Fetch
' UNION 查询 - 使用 Sql() 方式
db.Sql("SELECT name FROM users UNION SELECT name FROM admins").FetchQ3: Where 和 WhereLike 能同时使用吗?
可以,它们都是 AND 条件,会自动合并:
vb
db.Table("users") _
.Where("dept=?", "IT") _
.WhereLike("name", "%张%") _
.RowRead
' 生成: WHERE dept='IT' AND name LIKE '%张%'Q4: OrWhere 的优先级如何?
OrWhere 用括号包裹,确保与 AND 条件正确组合:
vb
db.Table("users").Where("age>?", 18).OrWhere("role='VIP'").RowRead
' 生成: WHERE age > 18 OR (role='VIP')Q5: RowCreate 后能继续使用 Rs 编辑吗?
可以。RowCreate 后不自动重置构建器,允许你继续操作 Rs:
vb
With db.Table("users").RowCreate
.Rs!name = "张三"
If someCondition Then
.Rs!email = "zhang@test.com"
End If
.Rs.Update
End WithQ6: Page 和 Limit/Offset 有什么区别?
| 方法 | 适用场景 | 实现方式 |
|---|---|---|
Page(N,M) | 标准分页 | ADO PageSize/AbsolutePage,所有数据库通用 |
Limit(M) | 简单截断 | SQL LIMIT M,MySQL/MSSQL 语法适配 |
Offset(N) | 配合 Limit偏移 | SQL OFFSET N,MySQL/MSSQL 语法适配 |
不要同时使用 Page 和 Limit/Offset,选择其一即可。
Q7: 链式方法执行后状态会保留吗?
不会。终结方法(RowRead, RowCreate, RowUpdate, RowDelete, RowCount 等)执行后会自动调用 ResetBuilder 清除所有内部状态。下次链式调用需要重新从 Table() 开始。
最佳实践
1. 使用 With 简化链式调用
vb
' 推荐:With 结构清晰
With db.Table("users").Where("id=?", userId)
.Field "name", newName
.Field "age", newAge
.RowUpdate
End With
' 不推荐:散开写
db.Table "users"
db.Where "id=?", userId
db.Field "name", newName
db.Field "age", newAge
db.RowUpdate2. 优先使用链式参数转义
vb
' 推荐:Where 占位符自动转义
db.Table("users").Where("name=?", userName).RowRead
' 不推荐:手动拼接值
db.Table("users").Where("name='" & userName & "'").RowRead3. 始终为更新/删除设置条件
vb
' 安全:必须有 Where 条件
db.Table("users").Where("id=?", 1).RowUpdate
db.Table("users").Where("status=?", "expired").RowDelete
' 危险:没有条件会报错(构建器保护)
db.Table("users").RowUpdate ' 报错: no condition set4. 复杂查询用 Sql()
vb
' 链式适合:标准 CRUD、简单条件、排序、分页
db.Table("users").Where("age>?", 18).OrderByDesc("id").Page(1, 10).RowRead
' Sql() 适合:子查询、UNION、窗口函数、复杂表达式
db.Sql("SELECT * FROM (SELECT id,name FROM users UNION SELECT id,name FROM admins) t").Fetch最后更新: 2026-06-26