【Golang】データベース操作 sqlite3

#【Golang】データベース操作 sqlite3
Golangの基礎学習〜Webアプリケーション作成までの学習を終えたので、復習を兼ねてまとめていく。 基礎〜応用まで。

```
package main

/*
sqliteをインストールする際の手順の確認

PostgreSQL　は次回。ほぼ同じだが。

インストール済
https://qiita.com/__init__/items/2edfc7acf11234e5b1aa

Mac
# brew のインストール
-> https://brew.sh/index_ja

# sqlite3 をインストール
brew install sqlite

Install gcc C言語のライブラリをインポートするので、GOがビルドする際に必要
-> https://developer.apple.com/xcode

# ドライバのインストール
go get github.com/mattn/go-sqlite3

# 不要だが一応
export CGO_ENABLED=1

Windows
Install sqlite3
-> https://www.sqlite.org/download.html

Install gcc
-> http://tdm-gcc.tdragon.net/

# ドライバのインストール
go get github.com/mattn/go-sqlite3

# 不要だが一応
set CGO_ENABLED=1

macでバージョン確認
# sqlite3 インストール確認
$ sqlite3
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite>
# sqlite3 を抜ける
sqlite> .exit

# xcode のコマンドラインツールの確認
$ xcode-select --install
xcode-select: error: command line tools are already installed, use "Software Update" to install updates

# gcc インストール確認
$ gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 10.0.0 (clang-1000.11.45.5)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin


//データベース操作


*/

import (
	"database/sql"
	"fmt"
	"log"

	//インポート _にしないとコンパイルエラーになる。使用しない為
	_ "github.com/mattn/go-sqlite3"
)

var DbConnection *sql.DB

type Person struct {
	Name string
	Age  int
}

func main() {
	//1
	//DBを開く  なければ作成される
	DbConnection, _ := sql.Open("sqlite3", "./example.sql")
	//終わったら閉じる
	defer DbConnection.Close()
	//DB作成 SQLコマンド
	cmd := `CREATE TABLE IF NOT EXISTS person(
		name STRING,
		age  INT)`

	//実行 結果は返ってこない為、_にする
	_, err := DbConnection.Exec(cmd)

	//エラーハンドリング
	if err != nil {
		fmt.Println("エラー")
		log.Fatalln(err)
	}

	//ターミナル
	//sqlite3
	//.table
	//SELECT * FROM tablename;
	//で確認

	//2 CRUD処理
	//Create
	//データを追加
	//VALUES (?, ?)  値は後で渡す。セキュリテイの関係でこのようにする方がいい
	//SQLインジェクション 悪意あるコマンドでDBが操作されてしまうのを防ぐ ?でエスケープしてくれる
	cmd = "INSERT INTO person (name, age) VALUES (?, ?)"
	//実行
	//レコードを取得する必要のない、クエリはExecメソッドを使う
	//第二引数からは、コマンド?部の値
	_, err = DbConnection.Exec(cmd, "Nancy", 20)
	if err != nil {
		log.Fatalln(err)
	}

	//Update
	//データの更新 Mike が存在する場合
	cmd = "UPDATE person SET age = ? WHERE name = ?"
	_, err = DbConnection.Exec(cmd, 25, "Mike")
	if err != nil {
		log.Fatalln(err)
	}

	//Read
	//Get  All
	//マルチセレクト
	//データ全てをループで表示
	//Queryは全て取得する
	cmd = "SELECT * FROM person"
	rows, _ := DbConnection.Query(cmd)
	defer rows.Close()
	//structを作成
	var pp []Person
	//取得したデータをループでスライスに追加　for rows.Next()
	for rows.Next() {
		var p Person
		//scan データ追加
		err := rows.Scan(&p.Name, &p.Age)
		if err != nil {
			log.Println(err)
		}
		pp = append(pp, p)
	}
	err = rows.Err()
	if err != nil {
		log.Fatalln(err)
	}
	//表示
	for _, p := range pp {
		fmt.Println(p.Name, p.Age)
	}

	//特定のデータを取得
	cmd = "SELECT * FROM person where age = ?"
	//age = 20にして実行
	//QueryRowは最初の一件だけ取得する。
	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)

	//Delete
	//データの削除  全て
	cmd = "DELETE FROM person WHERE name = ?"
	_, err = DbConnection.Exec(cmd, "Nancy")
	if err != nil {
		log.Fatalln(err)
	}

	//マルチセレクト  テーブルもSQLインジェクション対策
	//こちらを推奨
	//データを構造体に入れて表示
	//テーブルはSQLインジェクション対策が使えない
	tableName := "person"
	//テーブル名指定は?が使えない為、%sを使う。
	//後に対応されるかも？
	cmd = fmt.Sprintf("SELECT * FROM %s", tableName)
	rows1, _ := DbConnection.Query(cmd)
	defer rows1.Close()
	var pp1 []Person
	//パターンとして覚える
	for rows1.Next() {
		var p Person
		//データを構造体に追加
		err := rows1.Scan(&p.Name, &p.Age)
		if err != nil {
			log.Println(err)
		}
		//ppに追加
		pp1 = append(pp1, p)
	}
	//まとめてエラーチェック
	err = rows1.Err()
	if err != nil {
		//エラーなら終了
		log.Fatalln(err)
	}
	for _, p := range pp1 {
		fmt.Println(p.Name, p.Age)
	}
}

```