Golang Common Table Expressions PostgreSQL MySQL
WITH
Most Bun queries support CTEs via With
method:
q1 := db.NewSelect()
q2 := db.NewSelect()
q := db.NewInsert().
With("q1", q1).
With("q2", q2).
Table("q1", "q2")
For example, you can use CTEs to bulk-delete rows that match some predicates:
const limit = 1000
for {
subq := db.NewSelect().
Model((*Comment)(nil)).
Where("created_at < now() - interval '90 day'").
Limit(limit)
res, err := db.NewDelete().
With("todo", subq).
Model((*Comment)(nil)).
Table("todo").
Where("comment.id = todo.id").
Exec(ctx)
if err != nil {
panic(err)
}
num, err := res.RowsAffected()
if err != nil {
panic(err)
}
if num < limit {
break
}
}
WITH todo AS (
SELECT * FROM comments
WHERE created_at < now() - interval '90 day'
LIMIT 1000
)
DELETE FROM comments AS comment USING todo
WHERE comment.id = todo.id
Or copy data between tables:
src := db.NewSelect().Model((*Comment)(nil))
res, err := db.NewInsert().
With("src", src).
Table("comments_backup", "src").
Exec(ctx)
WITH src AS (SELECT * FROM comments)
INSERT INTO comments_backups SELECT * FROM src
VALUES
Bun also provides ValuesQuery to help building CTEs:
values := db.NewValues(&[]*Book{book1, book2})
res, err := db.NewUpdate().
With("_data", values).
Model((*Book)(nil)).
Table("_data").
Set("title = _data.title").
Set("text = _data.text").
Where("book.id = _data.id").
Exec(ctx)
WITH _data (id, title, text) AS (VALUES (1, 'title1', 'text1'), (2, 'title2', 'text2'))
UPDATE books AS book
SET title = _data.title, text = _data.text
FROM _data
WHERE book.id = _data.id
WithOrder
You can also use WithOrder to include row rank in values:
users := []User{
{ID: 1, "one@my.com"},
{ID: 2, "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