Common table expressions [PostgreSQL MySQL]

With

Most Bun queries support CTEs via With method:

  1. q1 := db.NewSelect()
  2. q2 := db.NewSelect()
  3. q := db.NewInsert().
  4. With("q1", q1).
  5. With("q2", q2).
  6. Table("q1", "q2")

For example, you can use CTEs to bulk-delete rows that match some predicates:

  1. const limit = 1000
  2. for {
  3. subq := db.NewSelect().
  4. Model((*Comment)(nil)).
  5. Where("created_at < now() - interval '90 day'").
  6. Limit(limit)
  7. res, err := db.NewDelete().
  8. With("todo", subq).
  9. Model((*Comment)(nil)).
  10. Table("todo").
  11. Where("comment.id = todo.id").
  12. Exec(ctx)
  13. if err != nil {
  14. panic(err)
  15. }
  16. num, err := res.RowsAffected()
  17. if err != nil {
  18. panic(err)
  19. }
  20. if num < limit {
  21. break
  22. }
  23. }
  1. WITH todo AS (
  2. SELECT * FROM comments
  3. WHERE created_at < now() - interval '90 day'
  4. LIMIT 1000
  5. )
  6. DELETE FROM comments AS comment USING todo
  7. WHERE comment.id = todo.id

Or copy data between tables:

  1. src := db.NewSelect().Model((*Comment)(nil))
  2. res, err := db.NewInsert().
  3. With("src", src).
  4. Table("comments_backup", "src").
  5. Exec(ctx)
  1. WITH src AS (SELECT * FROM comments)
  2. INSERT INTO comments_backups SELECT * FROM src

VALUES

Bun also provides ValuesQueryCommon table expressions - 图1open in new window to help building CTEs:

  1. values := db.NewValues([]*Book{book1, book2})
  2. res, err := db.NewUpdate().
  3. With("_data", values).
  4. Model((*Book)(nil)).
  5. Table("_data").
  6. Set("title = _data.title").
  7. Set("text = _data.text").
  8. Where("book.id = _data.id").
  9. Exec(ctx)
  1. WITH _data (id, title, text) AS (VALUES (1, 'title1', 'text1'), (2, 'title2', 'text2'))
  2. UPDATE books AS book
  3. SET title = _data.title, text = _data.text
  4. FROM _data
  5. WHERE book.id = _data.id

You can also use WithOrderCommon table expressions - 图2open in new window to include row rank in values:

  1. users := []User{
  2. {ID: 1, "one@my.com"},
  3. {ID: 2, "two@my.com"},
  4. }
  5. err := db.NewSelect().
  6. With("data", db.NewValues(&users).WithOrder()).
  7. Model(&users).
  8. Where("user.id = data.id").
  9. OrderExpr("data._order").
  10. Scan(ctx)
  1. WITH "data" ("id", "email", _order) AS (
  2. VALUES
  3. (42::BIGINT, 'one@my.com'::VARCHAR, 0),
  4. (43::BIGINT, 'two@my.com'::VARCHAR, 1)
  5. )
  6. SELECT "user"."id", "user"."email"
  7. FROM "users" AS "user"
  8. WHERE (user.id = data.id)
  9. ORDER BY data._order