【Go】学習メモ3:データベース操作(CREATE TABLE, INSERT, UPDATE, データ取得)

SQLiteを使用した簡単なDB操作について

サンプルとして
personという名前のテーブル(name:string, age:int)を作成して、
UPDATE, INSERT,データ取得を実行していきます。

前準備

windowsの場合sqlite, gcc, go-sqlite3のインストールが必要になります。
この記事などが参考になるかと思います。
qiita.com

インポートするパッケージ

sqlite を使用するために必要なパッケージのインポート
"github.com/mattn/go-sqlite3"は直接コード内には登場しないですが、ビルドしてコンパイルしないとsqliteが使用できません。

package main

import (
	"database/sql"
	"log"

	_ "github.com/mattn/go-sqlite3"
)

func main内で使用する変数とテーブルのstructです。
ここのPersonというstructは後ほど作成するpersonテーブルからデータを取得する際に使います。

var DbConnection *sql.DB

type Person struct {
	Name string
	Age  int
}

DBConnectionを用意します。sqlite3:ドライバ
最後にDBを閉じるのでdefer でクローズ

func main() {
	DbConnection, _ := sql.Open("sqlite3", "./example.sql")
	defer DbConnection.Close()

CREATE コマンドとコマンドの実行
テーブル作成などの実行コマンドはExecで実行されます。

	cmd := `CREATE TABLE IF NOT EXISTS person(
			name STRING,
			age INT)`
	_, err := DbConnection.Exec(cmd)
	if err != nil {
		log.Fatalln(err)
	}

INSERT

INSERTの際はコマンドを記述する際に"?"を入れておき、
Exec内で"?"に対する値を入れることが出来ます。
SQLインジェクションの対策としてこのような書き方が勧められているそうです。
ただし、テーブル名を"?"で入力することはまだ対応されていないそうです。

	cmd = "INSERT INTO person (name, age) VALUES (?, ?)"
	_, err = DbConnection.Exec(cmd, "Mike", 24)
	if err != nil {
		log.Fatalln(err)
	}

UPDATE

UPDATEも同様に"?"による記述とExec実行可能です。
Exec内でUPDATEしたい値を入力します。

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

データ取得(マルチセレクト)

テーブルのデータを複数連続で取得したい場合は、マルチセレクトを用います。
DbConnection.Queryを使用しrowsにSQLコマンドを渡します。
予め ppとして定義したPersonのstructを用意しておきます。

	cmd = "SELECT * FROM person"
	rows, _ := DbConnection.Query(cmd)
	defer rows.Close()
	var pp []Person

rows.Next()でレコードごとにループで回します。
pをPersonのstructとして定義、
rows.Scan()にpのstructのアドレスを入れておくと値が格納されます。

	for rows.Next() {
		var p Person
		err := rows.Scan(&p.Name, &p.Age)
		if err != nil {
			log.Println(err)
		}
		pp = append(pp, p)
	}
	if err != nil {
		log.Fatalln(err)
	}

データ取得(シングルセレクト)

ある条件の値のみほしい場合はシングルセレクトで取得します。
シングルセレクトではコマンド内にINSERT文と同じように"?"を入力しておき
DbConnection.QueryRow()に検索値(この場合はage = 20が条件)を渡すことでレコードが取得できます。
エラーハンドリング内のsql.ErrNoRowsでは、レコードが存在しない場合はlog.Printlnで"No row"が出力されるようになっています。

	cmd = "SELECT * FROM person where age = ?"
	row := DbConnection.QueryRow(cmd, 20)
	var p Person
	err = row.Scan(&p.Name, &p.Age)
	if err != nil {
		if err == sql.ErrNoRows {
			log.Println("No row")
		} else {
			log.Println(err)
		}
	}
	fmt.Println(p.Name, p.Age)