データのクエリ

データを返す SQL 文を実行する場合は、`database/sql` パッケージに用意されている `Query` メソッドのいずれかを使用します。これらのメソッドはそれぞれ、`Scan` メソッドを使用して変数にデータをコピーできる `Row` または `Rows` を返します。たとえば、これらのメソッドを使用して `SELECT` 文を実行します。

データを返さないステートメントを実行する場合は、代わりに `Exec` または `ExecContext` メソッドを使用できます。詳細については、データを返さないステートメントの実行 を参照してください。

`database/sql` パッケージは、結果を取得するためのクエリを実行する 2 つの方法を提供します。

同じ SQL 文を繰り返し実行する場合は、プリペアドステートメントの使用を検討してください。詳細については、プリペアドステートメントの使用 を参照してください。

**注意:** `fmt.Sprintf` などの文字列フォーマット関数を使用して SQL 文を組み立てないでください! SQL インジェクションのリスクが生じる可能性があります。詳細については、SQL インジェクションのリスクの回避 を参照してください。

単一行のクエリ

`QueryRow` は、一意の ID でデータを検索する場合など、最大で 1 つのデータベース行を取得します。クエリによって複数の行が返された場合、`Scan` メソッドは最初の行以外はすべて破棄します。

`QueryRowContext` は `QueryRow` と同様に機能しますが、`context.Context` 引数を使用します。詳細については、進行中の操作のキャンセル を参照してください。

次の例では、クエリを使用して、購入をサポートするのに十分な在庫があるかどうかを確認します。SQL 文は、十分な場合は `true` を、そうでない場合は `false` を返します。`Row.Scan` は、ポインタを介してブール値の戻り値を `enough` 変数にコピーします。

func canPurchase(id int, quantity int) (bool, error) {
    var enough bool
    // 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
}

**注:** プリペアドステートメントのパラメータプレースホルダーは、使用している DBMS とドライバによって異なります。たとえば、Postgres 用の pq ドライバ は、`?` の代わりに `$1` のようなプレースホルダーが必要です。

エラー処理

`QueryRow` 自体はエラーを返しません。代わりに、`Scan` は、ルックアップとスキャンの組み合わせによるエラーを報告します。クエリが行を検出しない場合は、`sql.ErrNoRows` を返します。

単一行を返す関数

関数 説明
DB.QueryRow
DB.QueryRowContext
単一行クエリを分離して実行します。
Tx.QueryRow
Tx.QueryRowContext
より大きなトランザクション内で単一行クエリを実行します。詳細については、トランザクションの実行 を参照してください。
Stmt.QueryRow
Stmt.QueryRowContext
既に準備されたステートメントを使用して単一行クエリを実行します。詳細については、プリペアドステートメントの使用 を参照してください。
Conn.QueryRowContext 予約済み接続で使用します。詳細については、接続の管理 を参照してください。

複数行のクエリ

`Query` または `QueryContext` を使用して複数行のクエリを実行できます。これらは、クエリ結果を表す `Rows` を返します。コードは、`Rows.Next` を使用して返された行を反復処理します。各反復処理は `Scan` を呼び出して、列の値を変数にコピーします。

`QueryContext` は `Query` と同様に機能しますが、`context.Context` 引数を使用します。詳細については、進行中の操作のキャンセル を参照してください。

次の例では、指定されたアーティストのアルバムを返すクエリを実行します。アルバムは `sql.Rows` で返されます。コードは `Rows.Scan` を使用して、ポインタで表される変数に列の値をコピーします。

func albumsByArtist(artist string) ([]Album, error) {
    rows, err := db.Query("SELECT * FROM album WHERE artist = ?", artist)
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    // An album slice to hold data from returned rows.
    var albums []Album

    // 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
}

`rows.Close` への遅延呼び出しに注意してください。これは、関数がどのように戻っても、行によって保持されているすべてのリソースを解放します。行を最後までループすると暗黙的に閉じられますが、`defer` を使用して、何が起きても `rows` が閉じられるようにすることをお勧めします。

**注:** プリペアドステートメントのパラメータプレースホルダーは、使用している DBMS とドライバによって異なります。たとえば、Postgres 用の pq ドライバ は、`?` の代わりに `$1` のようなプレースホルダーが必要です。

エラー処理

クエリ結果のループ後、`sql.Rows` からのエラーを確認してください。クエリが失敗した場合、コードはこの方法でそれを検出します。

複数行を返す関数

関数 説明
DB.Query
DB.QueryContext
クエリを分離して実行します。
Tx.Query
Tx.QueryContext
より大きなトランザクション内でクエリを実行します。詳細については、トランザクションの実行 を参照してください。
Stmt.Query
Stmt.QueryContext
既に準備されたステートメントを使用してクエリを実行します。詳細については、プリペアドステートメントの使用 を参照してください。
Conn.QueryContext 予約済み接続で使用します。詳細については、接続の管理 を参照してください。

NULL 許容列値の処理

`database/sql` パッケージは、列の値が NULL の可能性がある場合に `Scan` 関数の引数として使用できる、いくつかの特別な型を提供します。それぞれには、値が NULL でないかどうかを報告する `Valid` フィールドと、そうでない場合は値を保持するフィールドが含まれています。

次の例のコードは、顧客名を照会します。名前の値が NULL の場合、コードはアプリケーションで使用する別の値を代用します。

var s sql.NullString
err := db.QueryRow("SELECT name FROM customer WHERE id = ?", id).Scan(&s)
if err != nil {
    log.Fatal(err)
}

// Find customer name, using placeholder if not present.
name := "Valued Customer"
if s.Valid {
    name = s.String
}

`sql` パッケージリファレンスで各型について詳細を確認してください

列からのデータの取得

クエリによって返された行をループする場合、`Rows.Scan` リファレンスで説明されているように、`Scan` を使用して行の列の値を Go の値にコピーします。

SQL `INT` から Go `int` への変換など、すべてのドライバでサポートされている基本的なデータ変換セットがあります。一部のドライバはこの変換セットを拡張しています。詳細については、個々のドライバのドキュメントを参照してください。

ご想像のとおり、`Scan` は列の型から類似の Go の型に変換します。たとえば、`Scan` は SQL `CHAR`、`VARCHAR`、および `TEXT` から Go `string` に変換します。ただし、`Scan` は、列の値に適した別の Go の型への変換も実行します。たとえば、列が常に数値を含む `VARCHAR` の場合、`int` などの数値 Go の型を指定して値を受け取ることができます。`Scan` は `strconv.Atoi` を使用して変換します。

`Scan` 関数によって行われる変換の詳細については、`Rows.Scan` リファレンスを参照してください。

複数の結果セットの処理

データベース操作で複数の結果セットが返される可能性がある場合は、`Rows.NextResultSet` を使用してそれらを取得できます。これは、たとえば、複数のテーブルを個別に照会し、それぞれに結果セットを返す SQL を送信する場合に役立ちます。

`Rows.NextResultSet` は、`Rows.Next` の呼び出しがその次のセットから最初の行を取得するように、次の結果セットを準備します。次の結果セットがあるかどうかを示すブール値を返します。

次の例のコードは、`DB.Query` を使用して 2 つの SQL 文を実行します。最初の結果セットは、プロシージャの最初のクエリからのもので、`album` テーブルのすべての行を取得します。次の結果セットは 2 番目のクエリからのもので、`song` テーブルから行を取得します。

rows, err := db.Query("SELECT * from album; SELECT * from song;")
if err != nil {
    log.Fatal(err)
}
defer rows.Close()

// Loop through the first result set.
for rows.Next() {
    // Handle result set.
}

// Advance to next result set.
rows.NextResultSet()

// Loop through the second result set.
for rows.Next() {
    // Handle second set.
}

// Check for any error in either result set.
if err := rows.Err(); err != nil {
    log.Fatal(err)
}