Querying For Data - The Go Programming Language
Querying For Data - The Go Programming Language
When executing an SQL statement that returns data, use one of the Query methods provided in
the database/sql package. Each of these returns a Row or Rows whose data you can copy to
variables using the Scan method. You’d use these methods to, for example, execute SELECT
statements.
When executing a statement that doesn’t return data, you can use an Exec or ExecContext
method instead. For more, see Executing statements that don’t return data.
The database/sql package provides two ways to execute a query for results.
Querying for a single row – QueryRow returns at most a single Row from the database. For
more, see Querying for a single row.
Querying for multiple rows – Query returns all matching rows as a Rows struct your code
can loop over. For more, see Querying for multiple rows.
If your code will be executing the same SQL statement repeatedly, consider using a prepared
statement. For more, see Using prepared statements.
Caution: Don’t use string formatting functions such as fmt.Sprintf to assemble an SQL
statement! You could introduce an SQL injection risk. For more, see Avoiding SQL injection risk.
QueryRow retrieves at most a single database row, such as when you want to look up data by a
unique ID. If multiple rows are returned by the query, the Scan method discards all but the first.
QueryRowContext works like QueryRow but with a context.Context argument. For more, see
Canceling in-progress operations.
The following example uses a query to find out if there’s enough inventory to support a purchase.
The SQL statement returns true if there’s enough, false if not. Row.Scan copies the boolean
return value into the enough variable through a pointer.
https://go.dev/doc/database/querying 1/5
8/27/24, 9:07 PM Querying for data - The Go Programming Language
// Query for a value based on a single row.
if err := db.QueryRow("SELECT (quantity >= ?) from album where id = ?",
quantity, id).Scan(&enough); err != nil {
if err == sql.ErrNoRows {
return false, fmt.Errorf("canPurchase %d: unknown album", id)
}
return false, fmt.Errorf("canPurchase %d: %v", id, err)
}
return enough, nil
}
Note: Parameter placeholders in prepared statements vary depending on the DBMS and driver
you’re using. For example, the pq driver for Postgres requires a placeholder like $1 instead of ?.
Handling errors
QueryRow itself returns no error. Instead, Scan reports any error from the combined lookup and
scan. It returns sql.ErrNoRows when the query finds no rows.
Function Description
Tx.QueryRow Run a single-row query inside a larger transaction. For more, see Executing
Tx.QueryRowContext transactions.
Stmt.QueryRow Run a single-row query using an already-prepared statement. For more, see
Stmt.QueryRowContext Using prepared statements.
Conn.QueryRowContext For use with reserved connections. For more, see Managing connections.
You can query for multiple rows using Query or QueryContext, which return a Rows representing
the query results. Your code iterates over the returned rows using Rows.Next. Each iteration calls
Scan to copy column values into variables.
QueryContext works like Query but with a context.Context argument. For more, see Canceling
in-progress operations.
The following example executes a query to return the albums by a specified artist. The albums are
returned in an sql.Rows. The code uses Rows.Scan to copy column values into variables
represented by pointers.
https://go.dev/doc/database/querying 2/5
8/27/24, 9:07 PM Querying for data - The Go Programming Language
// Loop through rows, using Scan to assign column data to struct fields.
for rows.Next() {
var alb Album
if err := rows.Scan(&alb.ID, &alb.Title, &alb.Artist,
&alb.Price, &alb.Quantity); err != nil {
return albums, err
}
albums = append(albums, alb)
}
if err = rows.Err(); err != nil {
return albums, err
}
return albums, nil
}
Note the deferred call to rows.Close. This releases any resources held by the rows no matter
how the function returns. Looping all the way through the rows also closes it implicitly, but it is
better to use defer to make sure rows is closed no matter what.
Note: Parameter placeholders in prepared statements vary depending on the DBMS and driver
you’re using. For example, the pq driver for Postgres requires a placeholder like $1 instead of ?.
Handling errors
Be sure to check for an error from sql.Rows after looping over query results. If the query failed,
this is how your code finds out.
Function Description
Tx.Query Run a query inside a larger transaction. For more, see Executing transactions.
Tx.QueryContext
https://go.dev/doc/database/querying 3/5
8/27/24, 9:07 PM Querying for data - The Go Programming Language
Function Description
Stmt.Query Run a query using an already-prepared statement. For more, see Using
Stmt.QueryContext prepared statements.
Conn.QueryContext For use with reserved connections. For more, see Managing connections.
The database/sql package provides several special types you can use as arguments for the Scan
function when a column’s value might be null. Each includes a Valid field that reports whether
the value is non-null, and a field holding the value if so.
Code in the following example queries for a customer name. If the name value is null, the code
substitutes another value for use in the application.
var s sql.NullString
err := db.QueryRow("SELECT name FROM customer WHERE id = ?", id).Scan(&s)
if err != nil {
log.Fatal(err)
}
NullBool
NullFloat64
NullInt32
NullInt64
NullString
NullTime
When looping over the rows returned by a query, you use Scan to copy a row’s column values
into Go values, as described in the Rows.Scan reference.
There is a base set of data conversions supported by all drivers, such as converting SQL INT to Go
int. Some drivers extend this set of conversions; see each individual driver’s documentation for
details.
https://go.dev/doc/database/querying 4/5
8/27/24, 9:07 PM Querying for data - The Go Programming Language
As you might expect, Scan will convert from column types to Go types that are similar. For
example, Scan will convert from SQL CHAR, VARCHAR, and TEXT to Go string. However, Scan will
also perform a conversion to another Go type that is a good fit for the column value. For example,
if the column is a VARCHAR that will always contain a number, you can specify a numeric Go type,
such as int, to receive the value, and Scan will convert it using strconv.Atoi for you.
For more detail about conversions made by the Scan function, see the Rows.Scan reference.
When your database operation might return multiple result sets, you can retrieve those by using
Rows.NextResultSet. This can be useful, for example, when you’re sending SQL that separately
queries multiple tables, returning a result set for each.
Rows.NextResultSet prepares the next result set so that a call to Rows.Next retrieves the first
row from that next set. It returns a boolean indicating whether there is a next result set at all.
Code in the following example uses DB.Query to execute two SQL statements. The first result set
is from the first query in the procedure, retrieving all of the rows in the album table. The next
result set is from the second query, retrieving rows from the song table.
https://go.dev/doc/database/querying 5/5