Documentation ¶
Overview ¶
Package sqlf is an SQL statement builder and executor.
SQL Statement Builder ¶
sqlf statement builder provides a way to:
- Combine SQL statements from fragments of raw SQL and arguments that match those fragments,
- Map columns to variables to be referenced by Scan,
- Convert ? placeholders into numbered ones for PostgreSQL ($1, $2, etc).
Example ¶
package main import ( "context" "database/sql" "fmt" "github.com/leporo/sqlf" ) type dummyDB int func (db *dummyDB) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { return nil, nil } func (db *dummyDB) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) { return nil, nil } func (db *dummyDB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row { return nil } var db = new(dummyDB) var ctx = context.Background() func main() { 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)")). // Map query fields to variables 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"). // Execute the query QueryAndClose(ctx, db, func(row *sql.Rows) { // Callback function is called for every returned row. // Row values are scanned automatically to bound variables. fmt.Printf("%s\t%s\t%d\t$%.2f\n", region, product, productUnits, productSales) }) if err != nil { panic(err) } }
Output:
Index ¶
- func SetDialect(newDefaultDialect *Dialect)
- type Dialect
- func (d *Dialect) ClearCache()
- func (b *Dialect) DeleteFrom(tableName string) *Stmt
- func (b *Dialect) From(expr string, args ...interface{}) *Stmt
- func (b *Dialect) InsertInto(tableName string) *Stmt
- func (b *Dialect) New(verb string, args ...interface{}) *Stmt
- func (b *Dialect) Select(expr string, args ...interface{}) *Stmt
- func (b *Dialect) Update(tableName string) *Stmt
- func (b *Dialect) With(queryName string, query *Stmt) *Stmt
- type Executor
- type Stmt
- func DeleteFrom(tableName string) *Stmt
- func From(expr string, args ...interface{}) *Stmt
- func InsertInto(tableName string) *Stmt
- func New(verb string, args ...interface{}) *Stmt
- func Select(expr string, args ...interface{}) *Stmt
- func Update(tableName string) *Stmt
- func With(queryName string, query *Stmt) *Stmt
- func (q *Stmt) Args() []interface{}
- func (q *Stmt) Bind(data interface{}) *Stmt
- func (q *Stmt) Clause(expr string, args ...interface{}) *Stmt
- func (q *Stmt) Clone() *Stmt
- func (q *Stmt) Close()
- func (q *Stmt) DeleteFrom(tableName string) *Stmt
- func (q *Stmt) Dest() []interface{}
- func (q *Stmt) Exec(ctx context.Context, db Executor) (sql.Result, error)
- func (q *Stmt) ExecAndClose(ctx context.Context, db Executor) (sql.Result, error)
- func (q *Stmt) Expr(expr string, args ...interface{}) *Stmt
- func (q *Stmt) From(expr string, args ...interface{}) *Stmt
- func (q *Stmt) FullJoin(table, on string) *Stmt
- func (q *Stmt) GroupBy(expr string) *Stmt
- func (q *Stmt) Having(expr string, args ...interface{}) *Stmt
- func (q *Stmt) In(args ...interface{}) *Stmt
- func (q *Stmt) InsertInto(tableName string) *Stmt
- func (q *Stmt) Invalidate()
- func (q *Stmt) Join(table, on string) *Stmt
- func (q *Stmt) LeftJoin(table, on string) *Stmt
- func (q *Stmt) Limit(limit interface{}) *Stmt
- func (q *Stmt) NewRow() newRow
- func (q *Stmt) Offset(offset interface{}) *Stmt
- func (q *Stmt) OrderBy(expr ...string) *Stmt
- func (q *Stmt) Paginate(page, pageSize int) *Stmt
- func (q *Stmt) Query(ctx context.Context, db Executor, handler func(rows *sql.Rows)) error
- func (q *Stmt) QueryAndClose(ctx context.Context, db Executor, handler func(rows *sql.Rows)) error
- func (q *Stmt) QueryRow(ctx context.Context, db Executor) error
- func (q *Stmt) QueryRowAndClose(ctx context.Context, db Executor) error
- func (q *Stmt) Returning(expr string) *Stmt
- func (q *Stmt) RightJoin(table, on string) *Stmt
- func (q *Stmt) Select(expr string, args ...interface{}) *Stmt
- func (q *Stmt) Set(field string, value interface{}) *Stmt
- func (q *Stmt) SetExpr(field, expr string, args ...interface{}) *Stmt
- func (q *Stmt) String() string
- func (q *Stmt) SubQuery(prefix, suffix string, query *Stmt) *Stmt
- func (q *Stmt) To(dest ...interface{}) *Stmt
- func (q *Stmt) Union(all bool, query *Stmt) *Stmt
- func (q *Stmt) Update(tableName string) *Stmt
- func (q *Stmt) Where(expr string, args ...interface{}) *Stmt
- func (q *Stmt) With(queryName string, query *Stmt) *Stmt
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func SetDialect ¶
func SetDialect(newDefaultDialect *Dialect)
SetDialect selects a Dialect to be used by default.
Dialect can be one of sqlf.NoDialect or sqlf.PostgreSQL
sqlf.SetDialect(sqlf.PostgreSQL)
Types ¶
type Dialect ¶
type Dialect struct {
// contains filtered or unexported fields
}
Dialect defines the method SQL statement is to be built.
NoDialect is a default statement builder mode. No SQL fragments will be altered. PostgreSQL mode can be set for a statement:
q := sqlf.PostgreSQL.From("table").Select("field") ... q.Close()
or as default mode:
sqlf.SetDialect(sqlf.PostgreSQL) ... q := sqlf.From("table").Select("field") q.Close()
When PostgreSQL mode is activated, ? placeholders are replaced with numbered positional arguments like $1, $2...
func (*Dialect) ClearCache ¶ added in v1.3.0
func (d *Dialect) ClearCache()
ClearCache clears the statement cache.
In most cases you don't need to care about it. It's there to let caller free memory when a caller executes zillions of unique SQL statements.
func (*Dialect) DeleteFrom ¶
DeleteFrom starts a DELETE statement.
func (*Dialect) InsertInto ¶
InsertInto starts an INSERT statement.
func (*Dialect) New ¶
New starts an SQL statement with an arbitrary verb.
Use From, Select, InsertInto or DeleteFrom methods to create an instance of an SQL statement builder for common statements.
func (*Dialect) Select ¶
Select starts a SELECT statement.
Consider using From method to start a SELECT statement - you may find it easier to read and maintain.
type Executor ¶
type Executor interface { ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row }
Executor performs SQL queries. It's an interface accepted by Query, QueryRow and Exec methods. Both sql.DB, sql.Conn and sql.Tx can be passed as executor.
type Stmt ¶
type Stmt struct {
// contains filtered or unexported fields
}
Stmt provides a set of helper methods for SQL statement building and execution.
Use one of the following methods to create a SQL statement builder instance:
sqlf.From("table") sqlf.Select("field") sqlf.InsertInto("table") sqlf.Update("table") sqlf.DeleteFrom("table")
For other SQL statements use New:
q := sqlf.New("TRUNCATE") for _, table := range tablesToBeEmptied { q.Expr(table) } err := q.ExecAndClose(ctx, db) if err != nil { panic(err) }
func DeleteFrom ¶
DeleteFrom starts a DELETE statement.
err := sqlf.DeleteFrom("table").Where("id = ?", id).ExecAndClose(ctx, db)
func From ¶
From starts a SELECT statement.
var cnt int64 err := sqlf.From("table"). Select("COUNT(*)").To(&cnt) Where("value >= ?", 42). QueryRowAndClose(ctx, db) if err != nil { panic(err) }
func InsertInto ¶
InsertInto starts an INSERT statement.
var newId int64 err := sqlf.InsertInto("table"). Set("field", value). Returning("id").To(&newId). QueryRowAndClose(ctx, db) if err != nil { panic(err) }
func New ¶
New initializes a SQL statement builder instance with an arbitrary verb.
Use sqlf.Select(), sqlf.InsertInto(), sqlf.DeleteFrom() to start common SQL statements.
Use New for special cases like this:
q := sqlf.New("TRANCATE") for _, table := range tableNames { q.Expr(table) } q.Clause("RESTART IDENTITY") err := q.ExecAndClose(ctx, db) if err != nil { panic(err) }
func Select ¶
Select starts a SELECT statement.
var cnt int64 err := sqlf.Select("COUNT(*)").To(&cnt). From("table"). Where("value >= ?", 42). QueryRowAndClose(ctx, db) if err != nil { panic(err) }
Note that From method can also be used to start a SELECT statement.
func Update ¶
Update starts an UPDATE statement.
err := sqlf.Update("table"). Set("field1", "newvalue"). Where("id = ?", 42). ExecAndClose(ctx, db) if err != nil { panic(err) }
func With ¶ added in v1.3.0
With starts a statement prepended by WITH clause and closes a subquery passed as an argument.
func (*Stmt) Args ¶
func (q *Stmt) Args() []interface{}
Args returns the list of arguments to be passed to database driver for statement execution.
Do not access a slice returned by this method after Stmt is closed.
An array, a returned slice points to, can be altered by any method that adds a clause or an expression with arguments.
Make sure to make a copy of the returned slice if you need to preserve it.
func (*Stmt) Bind ¶ added in v1.2.0
Bind adds structure fields to SELECT statement. Structure fields have to be annotated with "db" tag. Reflect-based Bind is slightly slower than `Select("field").To(&record.field)` but provides an easier way to retrieve data.
Note: this method does no type checks and returns no errors.
Example ¶
package main import ( "context" "database/sql" "github.com/leporo/sqlf" ) type dummyDB int func (db *dummyDB) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { return nil, nil } func (db *dummyDB) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) { return nil, nil } func (db *dummyDB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row { return nil } var db = new(dummyDB) var ctx = context.Background() func main() { 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) } }
Output:
func (*Stmt) Clause ¶
Clause appends a raw SQL fragment to the statement.
Use it to add a raw SQL fragment like ON CONFLICT, ON DUPLICATE KEY, WINDOW, etc.
An SQL fragment added via Clause method appears after the last clause previously added. If called first, Clause method prepends a statement with a raw SQL.
Example ¶
package main import ( "fmt" "github.com/leporo/sqlf" ) func main() { q := sqlf.From("empsalary"). Select("sum(salary) OVER w"). Clause("WINDOW w AS (PARTITION BY depname ORDER BY salary DESC)") fmt.Println(q.String()) q.Close() }
Output: SELECT sum(salary) OVER w FROM empsalary WINDOW w AS (PARTITION BY depname ORDER BY salary DESC)
func (*Stmt) Close ¶
func (q *Stmt) Close()
Close puts buffers and other objects allocated to build an SQL statement back to pool for reuse by other Stmt instances.
Stmt instance should not be used after Close method call.
func (*Stmt) DeleteFrom ¶
DeleteFrom adds DELETE clause to a statement.
q.DeleteFrom("table").Where("id = ?", id)
Example ¶
package main import ( "fmt" "github.com/leporo/sqlf" ) func main() { q := sqlf.DeleteFrom("table").Where("id = ?", 42) fmt.Println(q.String()) fmt.Println(q.Args()) q.Close() }
Output: DELETE FROM table WHERE id = ? [42]
func (*Stmt) Dest ¶
func (q *Stmt) Dest() []interface{}
Dest returns a list of value pointers passed via To method calls. The order matches the constructed SQL statement.
Do not access a slice returned by this method after Stmt is closed.
Note that an array, a returned slice points to, can be altered by To method calls.
Make sure to make a copy if you need to preserve a slice returned by this method.
func (*Stmt) ExecAndClose ¶
ExecAndClose executes the statement and releases all the objects and buffers allocated by statement builder back to a pool.
Do not call any Stmt methods after this call.
func (*Stmt) Expr ¶
Expr appends an expression to the most recently added clause.
Expressions are separated with commas.
func (*Stmt) From ¶
From adds a FROM clause to statement.
Example ¶
package main import ( "fmt" "github.com/leporo/sqlf" ) func main() { q := sqlf.Select("*"). From(""). SubQuery( "(", ") counted_news", sqlf.From("news"). Select("id, section, header, score"). Select("row_number() OVER (PARTITION BY section ORDER BY score DESC) AS rating_in_section"). OrderBy("section, rating_in_section")). Where("rating_in_section <= 5") fmt.Println(q.String()) q.Close() }
Output: SELECT * FROM (SELECT id, section, header, score, row_number() OVER (PARTITION BY section ORDER BY score DESC) AS rating_in_section FROM news ORDER BY section, rating_in_section) counted_news WHERE rating_in_section <= 5
func (*Stmt) GroupBy ¶
GroupBy adds the GROUP BY clause to SELECT statement
Example ¶
package main import ( "fmt" "github.com/leporo/sqlf" ) func main() { q := sqlf.From("incomes"). Select("source, sum(amount) as s"). Where("amount > ?", 42). GroupBy("source") fmt.Println(q.String()) fmt.Println(q.Args()) q.Close() }
Output: SELECT source, sum(amount) as s FROM incomes WHERE amount > ? GROUP BY source [42]
func (*Stmt) Having ¶
Having adds the HAVING clause to SELECT statement
Example ¶
package main import ( "fmt" "github.com/leporo/sqlf" ) func main() { q := sqlf.From("incomes"). Select("source, sum(amount) as s"). Where("amount > ?", 42). GroupBy("source"). Having("s > ?", 100) fmt.Println(q.String()) fmt.Println(q.Args()) q.Close() }
Output: SELECT source, sum(amount) as s FROM incomes WHERE amount > ? GROUP BY source HAVING s > ? [42 100]
func (*Stmt) In ¶
In adds IN expression to the current filter.
In method must be called after a Where method call.
Example ¶
package main import ( "fmt" "github.com/leporo/sqlf" ) func main() { q := sqlf.From("tasks"). Select("id, status"). Where("status").In("new", "pending", "wip") fmt.Println(q.String()) fmt.Println(q.Args()) q.Close() }
Output: SELECT id, status FROM tasks WHERE status IN (?,?,?) [new pending wip]
func (*Stmt) InsertInto ¶
InsertInto adds INSERT INTO clause to a statement.
q.InsertInto("table")
tableName argument can be a SQL fragment:
q.InsertInto("table AS t")
Example ¶
package main import ( "fmt" "github.com/leporo/sqlf" ) func main() { q := sqlf.InsertInto("table"). Set("field1", "newvalue"). SetExpr("field2", "field2 + 1") fmt.Println(q.String()) fmt.Println(q.Args()) q.Close() }
Output: INSERT INTO table ( field1, field2 ) VALUES ( ?, field2 + 1 ) [newvalue]
func (*Stmt) Invalidate ¶
func (q *Stmt) Invalidate()
Invalidate forces a rebuild on next query execution.
Most likely you don't need to call this method directly.
func (*Stmt) Limit ¶
Limit adds a limit on number of returned rows
Example ¶
package main import ( "fmt" "github.com/leporo/sqlf" ) func main() { q := sqlf.Select("id").From("table").Limit(10) fmt.Println(q.String()) }
Output: SELECT id FROM table LIMIT ?
func (*Stmt) NewRow ¶ added in v1.4.0
func (q *Stmt) NewRow() newRow
NewRow method helps to construct a bulk INSERT statement.
The following code
q := stmt.InsertInto("table") for k, v := range entries { q.NewRow(). Set("key", k). Set("value", v) }
produces (assuming there were 2 key/value pairs at entries map):
INSERT INTO table ( key, value ) VALUES ( ?, ? ), ( ?, ? )
func (*Stmt) Offset ¶
Offset adds a limit on number of returned rows
Example ¶
package main import ( "fmt" "github.com/leporo/sqlf" ) func main() { q := sqlf.Select("id").From("table").Limit(10).Offset(10) fmt.Println(q.String()) }
Output: SELECT id FROM table LIMIT ? OFFSET ?
func (*Stmt) OrderBy ¶
OrderBy adds the ORDER BY clause to SELECT statement
Example ¶
package main import ( "fmt" "github.com/leporo/sqlf" ) func main() { q := sqlf.Select("id").From("table").OrderBy("id", "name DESC") fmt.Println(q.String()) }
Output: SELECT id FROM table ORDER BY id, name DESC
func (*Stmt) Paginate ¶
Paginate provides an easy way to set both offset and limit
Example ¶
package main import ( "fmt" "github.com/leporo/sqlf" ) func main() { q := sqlf.Select("id").From("table").Paginate(5, 10) fmt.Println(q.String(), q.Args()) q.Close() q = sqlf.Select("id").From("table").Paginate(1, 10) fmt.Println(q.String(), q.Args()) q.Close() // Zero and negative values are replaced with 1 q = sqlf.Select("id").From("table").Paginate(-1, -1) fmt.Println(q.String(), q.Args()) q.Close() }
Output: SELECT id FROM table LIMIT ? OFFSET ? [10 40] SELECT id FROM table LIMIT ? [10] SELECT id FROM table LIMIT ? [1]
func (*Stmt) Query ¶
Query executes the statement. For every row of a returned dataset it calls a handler function. If scan targets were set via To method calls, Query method executes rows.Scan right before calling a handler function.
func (*Stmt) QueryAndClose ¶
QueryAndClose executes the statement and releases all the resources that can be reused to a pool. Do not call any Stmt methods after this call. For every row of a returned dataset QueryAndClose executes a handler function. If scan targets were set via To method calls, QueryAndClose method executes rows.Scan right before calling a handler function.
func (*Stmt) QueryRow ¶
QueryRow executes the statement via Executor methods and scans values to variables bound via To method calls.
func (*Stmt) QueryRowAndClose ¶
QueryRowAndClose executes the statement via Executor methods and scans values to variables bound via To method calls. All the objects allocated by query builder are moved to a pool to be reused.
Do not call any Stmt methods after this call.
Example ¶
package main import ( "context" "database/sql" "github.com/leporo/sqlf" ) type dummyDB int func (db *dummyDB) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) { return nil, nil } func (db *dummyDB) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) { return nil, nil } func (db *dummyDB) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row { return nil } var db = new(dummyDB) var ctx = context.Background() func main() { 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) } }
Output:
func (*Stmt) Returning ¶
Returning adds a RETURNING clause to a statement
Example ¶
package main import ( "fmt" "github.com/leporo/sqlf" ) func main() { var newId int q := sqlf.InsertInto("table"). Set("field1", "newvalue"). Returning("id").To(&newId) fmt.Println(q.String(), q.Args()) q.Close() }
Output: INSERT INTO table ( field1 ) VALUES ( ? ) RETURNING id [newvalue]
func (*Stmt) Select ¶
Select adds a SELECT clause to a statement and/or appends an expression that defines columns of a resulting data set.
q := sqlf.Select("DISTINCT field1, field2").From("table")
Select can be called multiple times to add more columns:
q := sqlf.From("table").Select("field1") if needField2 { q.Select("field2") } // ... q.Close()
Use To method to bind variables to selected columns:
var ( num int name string ) res := sqlf.From("table"). Select("num, name").To(&num, &name). Where("id = ?", 42). QueryRowAndClose(ctx, db) if err != nil { panic(err) }
Note that a SELECT statement can also be started by a From method call.
func (*Stmt) Set ¶
Set method:
- Adds a column to the list of columns and a value to VALUES clause of INSERT statement,
- Adds an item to SET clause of an UPDATE statement.
q.Set("field", 32)
For INSERT statements a call to Set method generates both the list of columns and values to be inserted:
q := sqlf.InsertInto("table").Set("field", 42)
produces
INSERT INTO table (field) VALUES (42)
Do not use it to construct ON CONFLICT DO UPDATE SET or similar clauses. Use generic Clause and Expr methods instead:
q.Clause("ON CONFLICT DO UPDATE SET").Expr("column_name = ?", value)
func (*Stmt) SetExpr ¶
SetExpr is an extended version of Set method.
q.SetExpr("field", "field + 1") q.SetExpr("field", "? + ?", 31, 11)
Example ¶
package main import ( "fmt" "github.com/leporo/sqlf" ) func main() { q := sqlf.Update("table").SetExpr("field1", "field2 + 1").Where("id = ?", 42) fmt.Println(q.String()) fmt.Println(q.Args()) q.Close() }
Output: UPDATE table SET field1=field2 + 1 WHERE id = ? [42]
func (*Stmt) SubQuery ¶
SubQuery appends a sub query expression to a current clause.
SubQuery method call closes the Stmt passed as query parameter. Do not reuse it afterwards.
Example ¶
package main import ( "fmt" "github.com/leporo/sqlf" ) func main() { 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() }
Output: SELECT date, region, (SELECT date FROM orders po WHERE region = o.region AND id < o.id ORDER BY id DESC LIMIT 1) AS prev_order_date FROM orders o WHERE date > CURRENT_DATE - interval '1 day' ORDER BY id DESC
func (*Stmt) To ¶
To sets a scan target for columns to be selected.
Accepts value pointers to be passed to sql.Rows.Scan by Query and QueryRow methods.
var ( field1 int field2 string ) q := sqlf.From("table"). Select("field1").To(&field1). Select("field2").To(&field2) err := QueryRow(nil, db) q.Close() if err != nil { // ... }
To method MUST be called immediately after Select, Returning or other method that defines data to be returned.
func (*Stmt) Union ¶ added in v1.1.0
Union adds a UNION clause to the statement.
all argument controls if UNION ALL or UNION clause is to be constructed. Use UNION ALL if possible to get faster queries.
Example ¶
package main import ( "fmt" "github.com/leporo/sqlf" ) func main() { q := sqlf.From("tasks"). Select("id, status"). Where("status = ?", "new"). Union(true, sqlf.From("tasks"). Select("id, status"). Where("status = ?", "pending")). Union(true, sqlf.From("tasks"). Select("id, status"). Where("status = ?", "wip")). OrderBy("id") fmt.Println(q.String()) fmt.Println(q.Args()) q.Close() }
Output: SELECT id, status FROM tasks WHERE status = ? UNION ALL SELECT id, status FROM tasks WHERE status = ? UNION ALL SELECT id, status FROM tasks WHERE status = ? ORDER BY id [new pending wip]
func (*Stmt) Update ¶
Update adds UPDATE clause to a statement.
q.Update("table")
tableName argument can be a SQL fragment:
q.Update("ONLY table AS t")
Example ¶
package main import ( "fmt" "github.com/leporo/sqlf" ) func main() { q := sqlf.Update("table").Set("field1", "newvalue").Where("id = ?", 42) fmt.Println(q.String(), q.Args()) q.Close() }
Output: UPDATE table SET field1=? WHERE id = ? [newvalue 42]
func (*Stmt) Where ¶
Where adds a filter:
sqlf.From("users"). Select("id, name"). Where("email = ?", email). Where("is_active = 1")
func (*Stmt) With ¶
With prepends a statement with an WITH clause. With method calls a Close method of a given query, so make sure not to reuse it afterwards.
Example ¶
package main import ( "fmt" "github.com/leporo/sqlf" ) func main() { q := 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"). Select("product"). Select("SUM(quantity) AS product_units"). Select("SUM(amount) AS product_sales"). Where("region IN (SELECT region FROM top_regions)"). GroupBy("region, product") fmt.Println(q.String()) q.Close() }
Output: WITH regional_sales AS (SELECT region, SUM(amount) AS total_sales FROM orders GROUP BY region), top_regions AS (SELECT region FROM regional_sales WHERE total_sales > (SELECT SUM(total_sales)/10 FROM regional_sales)) SELECT region, product, SUM(quantity) AS product_units, SUM(amount) AS product_sales FROM orders WHERE region IN (SELECT region FROM top_regions) GROUP BY region, product