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 ValuesQueryopen in new window 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 WithOrderopen in new window 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