技術向上

プログラミングの学び、気になるテクノロジーやビジネストレンドを発信

sqlite3【Go】

go-sqlite3を使用します。
事前準備は sqlite3を使用する前の準備【Go】 - 技術向上 に記載しています。

CREATE

var DbConnection *sql.DB

func main() {
    DbConnection, err := sql.Open("sqlite3", "./example.sql")    // 第1引数はDriver、第2引数はデータベース名
    if err != nil {
        log.Fatalln(err)
    }
    defer DbConnection.Close()    // 必ず閉じる
    // バッククォートを使うことで複数行記載できる
    // 主キーにidを設定。INTではなくINTEGERである必要がある
    cmd := `CREATE TABLE IF NOT EXISTS person (
                id INTEGER primary key,
                name STRING,
                age INT)`
    _, err = DbConnection.Exec(cmd)    // 戻り値resultは使用しないため破棄
    if err != nil {
        log.Fatalln(err)
    }
}


上記作成したテーブルは、下記コマンドで確認できます。

sqlite> .table    // テーブル一覧を取得
sqlite> .schema    // 全テーブルの構造を取得
sqlite> .schema person    // テーブルpersonの構造を取得


INSERT

var DbConnection *sql.DB

func main() {
    DbConnection, err := sql.Open("sqlite3", "./example.sql")    // 第1引数はDriver、第2引数はデータベース名
    if err != nil {
        log.Fatalln(err)
    }
    defer DbConnection.Close()    // 必ず閉じる

    cmd := `INSERT INTO person (name, age) VALUES (?, ?)`    // SQLInjectionを回避するため、後から指定するものはPrintfではなく、?で指定
    _, err = DbConnection.Exec(cmd, "Mike", 25)
    if err != nil {
        log.Fatalln(err)
    }
}


コマンドで、テーブルの中身を検索できます。

sqlite> select * from person;


UPDATE

var DbConnection *sql.DB

func main() {
    DbConnection, err := sql.Open("sqlite3", "./example.sql")    // 第1引数はDriver、第2引数はデータベース名
    if err != nil {
        log.Fatalln(err)
    }
    defer DbConnection.Close()    // 必ず閉じる

    cmd := `UPDATE person SET age = ? WHERE name = ?`
    _, err = DbConnection.Exec(cmd, 26, "Mike")
    if err != nil {
        log.Fatalln(err)
    }
}


DELETE

var DbConnection *sql.DB

func main() {
    DbConnection, err := sql.Open("sqlite3", "./example.sql")    // 第1引数はDriver、第2引数はデータベース名
    if err != nil {
        log.Fatalln(err)
    }
    defer DbConnection.Close()    // 必ず閉じる

    cmd := `DELETE FROM person WHERE name = ?`
    _, err = DbConnection.Exec(cmd, "Mike")
    if err != nil {
        log.Fatalln(err)
    }
}


SELECT

対象のもの全てを抽出するパターン

var DbConnection *sql.DB

type Person struct {
    ID   int
    Name string
    Age  int
}

func main() {
    DbConnection, err := sql.Open("sqlite3", "./example.sql")    // 第1引数はDriver、第2引数はデータベース名
    if err != nil {
        log.Fatalln(err)
    }
    defer DbConnection.Close()    // 必ず閉じる

    cmd := `SELECT * FROM person WHERE age = ?`
    rows, err := DbConnection.Query(cmd, 26)    // 対象全件取得の場合は、Queryを使用
    defer rows.Close()
    var pp []Person
    if err != nil {
        log.Fatalln(err)
    }
    for rows.Next() {
        var p Person    // 取得結果1件ずつを格納する入れ物を用意
        _ = rows.Scan(&p.ID, &p.Name, &p.Age)    // Scan()の中身に結果をコピー(値変更のためポインタ渡し)。返り値errorは使用しないため、破棄。forループ終了後、まとめてエラー処理をする
        pp = append(pp, p)
    }
    err = rows.Err()    // forループ終了後にまとめてエラーハンドリング
    if err != nil {
        log.Fatalln(err)
    }
    for _, v := range pp {
        fmt.Println(v)
    }
}


対象のものから最初の1件を抽出するパターン

var DbConnection *sql.DB

type Person struct {
    ID   int
    Name string
    Age  int
}

func main() {
    DbConnection, err := sql.Open("sqlite3", "./example.sql")    // 第1引数はDriver、第2引数はデータベース名
    if err != nil {
        log.Fatalln(err)
    }
    defer DbConnection.Close()    // 必ず閉じる

    cmd := `SELECT * FROM person WHERE age = ?`
    row := DbConnection.QueryRow(cmd, 26)    // 対象1件取得の場合は、QueryRowを使用
    var p Person    // 取得結果を格納する入れ物を用意
    err = row.Scan(&p.ID, &p.Name, &p.Age)    // Scan()の中身に結果をコピー(値変更のためポインタ渡し)
    if err != nil {    // 1件でありforループは無いため、ここでエラーハンドリング
        if err == sql.ErrNoRows {    // errorは、取得対象が存在しないことを識別できる
            log.Println("No row")
        } else {
            log.Fatalln(err)
        }
    }
    fmt.Println(p)
}


補足 - テーブル名のコード内指定について

仕様上、テーブル名に「?」を使用することが、現時点ではできません。
テーブル名を変数として持たせるには、fmt.Sprintf()を使います。

...
var tableName = "person"
cmd := fmt.Sprintf(`SELECT * FROM %s`, tableName)
rows, err := DbConnection.Query(cmd)
...