Golang Where PostgreSQL MySQL
Basics
You can use arbitrary unsafe expressions in Where
:
q = q.Where("column LIKE 'hello%'")
To safely build dynamic WHERE clauses, use placeholders and bun.Ident
:
q = q.Where("? LIKE ?", bun.Ident("mycolumn"), "hello%")
QueryBuilder
Bun provides QueryBuilder interface which supports common methods required to build queries, for example:
func addWhere(q bun.QueryBuilder) bun.QueryBuilder {
return q.Where("id = ?", 123)
}
qb := db.NewSelect().QueryBuilder()
addWhere(qb)
qb := db.NewUpdate().QueryBuilder()
addWhere(qb)
qb := db.NewDelete().QueryBuilder()
addWhere(qb)
// Alternatively.
db.NewSelect().ApplyQueryBuilder(addWhere)
db.NewUpdate().ApplyQueryBuilder(addWhere)
db.NewDelete().ApplyQueryBuilder(addWhere)
Both the QueryBuilder
and ApplyQueryBuilder
functions return a struct of QueryBuilder interface type. Once your query is built you need to retrieve the original Query struct in order to be able to call Scan
or Exec
functions. To do that you have to Unwrap() your query builder struct and then cast it to desired type like so:
qb := db.NewSelect().QueryBuilder().Where("id = ?", 123)
selectQuery = qb.Unwrap().(*bun.SelectQuery)
WHERE IN
If you already have a list of ids, use bun.In
:
q = q.Where("user_id IN (?)", bun.In([]int64{1, 2, 3}))
You can also use subqueries:
subq := db.NewSelect().Model((*User)(nil)).Column("id").Where("active")
q = q.Where("user_id IN (?)", subq)
WherePK
WherePK
allows to auto-generate a WHERE clause using model primary keys:
users := []User{
{ID: 1},
{ID: 2},
{ID: 3},
}
err := db.NewSelect().Model(&users).WherePK().Scan(ctx)
SELECT * FROM users WHERE id IN (1, 2, 3)
WherePK
also accepts a list of columns that can be used instead of primary keys to indentify rows:
users := []User{
{Email: "one@my.com"},
{Email: "two@my.com"},
{Email: "three@my.com"},
}
err := db.NewSelect().Model(&users).WherePK("email").Scan(ctx)
SELECT * FROM users WHERE email IN ('one@my.com', 'two@my.com', 'three@my.com')
WHERE VALUES
You can build complex queries using CTE and VALUES
:
users := []User{
{ID: 1, Email: "one@my.com"},
{ID: 2, Email: "two@my.com"},
}
err := db.NewSelect().
With("data", db.NewValues(&users).WithOrder()).
Model(&users).
Where("user.id = data.id").
OrderExpr("data._order").
Scan(ctx)
WITH "data" ("id", "email", _order) AS (
VALUES
(42::BIGINT, 'one@my.com'::VARCHAR, 0),
(43::BIGINT, 'two@my.com'::VARCHAR, 1)
)
SELECT "user"."id", "user"."email"
FROM "users" AS "user"
WHERE (user.id = data.id)
ORDER BY data._order
Grouping
You can use WhereOr
to join conditions with logical OR
:
q = q.Where("id = 1").WhereOr("id = 2").WhereOr("id = 3")
To group conditions with parentheses, use WhereGroup
:
q = q.
WhereGroup(" AND ", func(q *bun.SelectQuery) *bun.SelectQuery {
return q.Where("id = 1").WhereOr("id = 2").WhereOr("id = 3")
}).
WhereGroup(" AND NOT ", func(q *bun.SelectQuery) *bun.SelectQuery {
return q.Where("active").WhereOr("archived")
})
WHERE (id = 1 OR id = 2 OR id = 3) AND NOT (active OR archived)