golang快速构建SQL查询语句插件库sqlf的使用
Golang 快速构建 SQL 查询语句插件库 sqlf 的使用
sqlf 是一个快速的 Go SQL 查询构建器。
sqlf 的功能
sqlf 可以:
- 帮助你在运行时高效构建 SQL 语句
- 安全地更改受影响列的数量和参数数量
- 在 SQL 语句中使用 SQL 表达式(如
UPDATE counters SET counter = counter + 1
) - 动态应用过滤器,添加 where 条件,更改结果排序等
- 安全地在 SQL 片段中使用
?
占位符 - sqlf 会根据需要将它们转换为 PostgreSQL 风格的$1, $2,...
占位符 - 像其他类似库一样,将结构体绑定到数据库列
- 提供方法使用任何
database/sql
兼容的驱动程序执行查询
sqlf 不提供的功能
sqlf 不是 ORM,你仍然需要使用原始 SQL。它不提供:
- 数据库模式迁移或任何其他数据库模式维护工具
- 查询参数、列名和表名的编译时类型检查
OR
子句的包装器- 帮助开发者定位 SQL 语句问题的原因
性能表现
sqlf 性能优异。为了最大化性能并最小化内存占用,sqlf 会重用为查询构建分配的内存。负载越重,sqlf 工作得越快。
使用示例
构建复杂语句
var (
region string
product string
productUnits int
productSales float64
)
sqlf.SetDialect(sqlf.PostgreSQL)
err := sqlf.From("orders").
With("regional_sales",
sqlf.From("orders").
Select("region, SUM(amount) AS total_sales").
GroupBy("region")).
With("top_regions",
sqlf.From("regional_sales").
Select("region").
Where("total_sales > (SELECT SUM(total_sales)/10 FROM regional_sales)")).
// 将查询字段映射到变量
Select("region").To(®ion).
Select("product").To(&product).
Select("SUM(quantity)").To(&productUnits).
Select("SUM(amount) AS product_sales").To(&productSales).
//
Where("region IN (SELECT region FROM top_regions)").
GroupBy("region, product").
OrderBy("product_sales DESC").
// 执行查询
QueryAndClose(ctx, db, func(row *sql.Rows){
// 为每个返回的行调用回调函数
// 行值会自动扫描到绑定的变量
fmt.Printf("%s\t%s\t%d\t$%.2f\n", region, product, productUnits, productSales)
})
if err != nil {
panic(err)
}
绑定结构体
type Offer struct {
Id int64 `db:"id"`
ProductId int64 `db:"product_id"`
Price float64 `db:"price"`
IsDeleted bool `db:"is_deleted"`
}
var o Offer
err := sqlf.From("offers").
Bind(&o).
Where("id = ?", 42).
QueryRowAndClose(ctx, db)
if err != nil {
panic(err)
}
检索到私有字段
type Offer struct {
id int64
productId int64
price float64
isDeleted bool
}
var o Offer
err := sqlf.From("offers").
Select("id").To(&o.id).
Select("product_id").To(&o.productId).
Select("price").To(&o.price).
Select("is_deleted").To(&o.isDeleted).
Where("id = ?", 42).
QueryRowAndClose(ctx, db)
if err != nil {
panic(err)
}
使用 sqlf.Stmt 构建基础查询
func (o *Offer) Select() *sqlf.Stmt {
return sqlf.From("products").
.Bind(o)
// 忽略标记为删除的记录
Where("is_deleted = false")
}
func (o Offer) Print() {
fmt.Printf("%d\t%s\t$%.2f\n", o.id, o.name, o.price)
}
var o Offer
// 获取报价数据
err := o.Select().
Where("id = ?", offerId).
QueryRowAndClose(ctx, db)
if err != nil {
panic(err)
}
o.Print()
// ...
// 选择并打印给定产品的5个最近放置的报价
err = o.Select().
Where("product_id = ?", productId).
OrderBy("id DESC").
Limit(5).
QueryAndClose(ctx, db, func(row *sql.Rows){
o.Print()
})
if err != nil {
panic(err)
}
// ...
值绑定
var (
minAmountRequested = true
maxAmount float64
minAmount float64
)
q := sqlf.From("offers").
Select("MAX(amount)").To(&maxAmount).
Where("is_deleted = false")
if minAmountRequested {
q.Select("MIN(amount)").To(&minAmount)
}
err := q.QueryRowAndClose(ctx, db)
if err != nil {
panic(err)
}
if minAmountRequested {
fmt.Printf("Cheapest offer: $%.2f\n", minAmount)
}
fmt.Printf("Most expensive offer: $%.2f\n", minAmount)
连接查询
var (
offerId int64
productName string
price float64
}
err := sqlf.From("offers o").
Select("o.id").To(&offerId).
Select("price").To(&price).
Where("is_deleted = false").
// 连接
LeftJoin("products p", "p.id = o.product_id").
// 将连接表中的列绑定到变量
Select("p.name").To(&productName).
// 打印前10个报价
OrderBy("price DEST").
Limit(10).
QueryAndClose(ctx, db, func(row *sql.Rows){
fmt.Printf("%d\t%s\t$%.2f\n", offerId, productName, price)
})
if err != nil {
panic(err)
}
子查询
q := sqlf.From("orders o").
Select("date, region").
SubQuery("(", ") AS prev_order_date",
sqlf.From("orders po").
Select("date").
Where("region = o.region").
Where("id < o.id").
OrderBy("id DESC").
Clause("LIMIT 1")).
Where("date > CURRENT_DATE - interval '1 day'").
OrderBy("id DESC")
fmt.Println(q.String())
q.Close()
联合查询
q := sqlf.From("tasks").
Select("id, status").
Where("status = ?", "new").
Union(true, sqlf.PostgreSQL.From("tasks").
Select("id, status").
Where("status = ?", "wip"))
// ...
q.Close()
插入数据
var userId int64
_, err := sqlf.InsertInto("users").
Set("email", "new@email.com").
Set("address", "320 Some Avenue, Somewhereville, GA, US").
Returning("id").To(&userId).
Clause("ON CONFLICT (email) DO UPDATE SET address = users.address").
QueryRowAndClose(ctx, db)
批量插入
_, err := sqlf.InsertInto("users").
NewRow().
Set("email", "first@email.com").
Set("address", "320 Some Avenue, Somewhereville, GA, US").
NewRow().
Set("email", "second@email.com").
Set("address", "320 Some Avenue, Somewhereville, GA, US").
ExecAndClose(ctx, db)
更新数据
_, err := sqlf.Update("users").
Set("email", "new@email.com").
ExecAndClose(ctx, db)
删除数据
_, err := sqlf.DeleteFrom("products").
Where("id = ?", 42)
ExecAndClose(ctx, db)
以上是 sqlf 库的主要功能和用法示例,它提供了简洁的 API 来构建和执行各种 SQL 查询。
更多关于golang快速构建SQL查询语句插件库sqlf的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang快速构建SQL查询语句插件库sqlf的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用sqlf快速构建SQL查询语句
sqlf是一个轻量级的Go语言SQL查询构建器,它提供了一种流畅、类型安全的方式来构建SQL查询语句。下面我将详细介绍sqlf的使用方法。
安装sqlf
go get github.com/leporo/sqlf
基本用法
简单查询
import "github.com/leporo/sqlf"
func main() {
query := sqlf.Select("id, name, email").
From("users").
Where("deleted_at IS NULL").
OrderBy("created_at DESC").
Limit(10)
sql, args := query.String(), query.Args()
fmt.Println(sql) // SELECT id, name, email FROM users WHERE deleted_at IS NULL ORDER BY created_at DESC LIMIT 10
fmt.Println(args) // []
}
带参数的查询
query := sqlf.Select("id, name, email").
From("users").
Where("age > ?", 18).
Where("status = ?", "active")
sql, args := query.String(), query.Args()
fmt.Println(sql) // SELECT id, name, email FROM users WHERE age > ? AND status = ?
fmt.Println(args) // [18 "active"]
复杂条件
query := sqlf.Select("*").
From("orders").
Where("customer_id = ?", 123).
Where("(status = ? OR status = ?)", "pending", "processing").
Where("created_at > ?", time.Now().AddDate(0, -1, 0))
sql, args := query.String(), query.Args()
插入数据
query := sqlf.InsertInto("users").
Set("name", "John Doe").
Set("email", "john@example.com").
Set("age", 30).
Set("created_at", time.Now())
sql, args := query.String(), query.Args()
fmt.Println(sql) // INSERT INTO users (name, email, age, created_at) VALUES (?, ?, ?, ?)
fmt.Println(args) // ["John Doe" "john@example.com" 30 "2023-05-01 12:00:00"]
更新数据
query := sqlf.Update("users").
Set("name", "Jane Doe").
Set("email", "jane@example.com").
Where("id = ?", 1)
sql, args := query.String(), query.Args()
删除数据
query := sqlf.DeleteFrom("users").
Where("id = ?", 1)
sql, args := query.String(), query.Args()
高级特性
子查询
subQuery := sqlf.Select("user_id").From("orders").Where("amount > ?", 100)
query := sqlf.Select("*").
From("users").
Where("id IN (?)", subQuery)
sql, args := query.String(), query.Args()
联合查询
query := sqlf.Select("u.id, u.name, o.order_date").
From("users u").
Join("orders o").On("u.id = o.user_id").
Where("u.status = ?", "active")
sql, args := query.String(), query.Args()
批量插入
query := sqlf.InsertInto("users").Columns("name", "email")
for _, user := range users {
query.Values(user.Name, user.Email)
}
sql, args := query.String(), query.Args()
原生SQL片段
query := sqlf.Select("*").
From("users").
Where("created_at BETWEEN ? AND ?", startDate, endDate).
Where(sqlf.Expr("LOWER(name) LIKE ?", "%"+strings.ToLower(search)+"%"))
sql, args := query.String(), query.Args()
执行查询
sqlf本身不处理数据库连接,但可以轻松与标准库或ORM配合使用:
import "database/sql"
db, _ := sql.Open("postgres", "connection_string")
query := sqlf.Select("*").From("users").Where("id = ?", 1)
rows, err := db.Query(query.String(), query.Args()...)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
// 处理结果...
优势总结
- 类型安全:通过参数化查询避免SQL注入
- 链式调用:流畅的API设计
- 轻量级:不依赖其他库
- 可读性强:代码即SQL,易于理解和维护
- 灵活性:支持原生SQL片段和复杂查询
sqlf特别适合需要灵活构建SQL查询但又不想引入完整ORM的场景,它保持了SQL的直观性同时提供了更好的构建方式。