🪽

[入門]GoでSQLite3を使いデータベース操作を行ってみる

2023/10/11に公開

インストール

今回はgo-sqlite3を利用する

sqlite

  1. brew install sqlite

  2. sqlite3
    下記のような表示となれば ok

SQLite version 3.39.5 2022-10-14 20:58:05
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite>
  1. .exitで抜ける

go-sqlite3

go get github.com/mattn/go-sqlite3

ただし、下記の通り、Go でビルドするにあたり C 言語のライブラリをインポートするため、CGO_ENABLE=1gcc のコンパイラが必要
既に入っている方は次のセクションをスキップしてください。

go-sqlite3 is cgo package. If you want to build your app using go-sqlite3, you need gcc. However, after you have built and installed go-sqlite3 with go install github.com/mattn/go-sqlite3 (which requires gcc), you can build your app without relying on gcc in future.
Important: because this is a CGO enabled package, you are required to set the environment variable CGO_ENABLED=1 and have a gcc compiler present within your path.

Xcode

  1. Xcode-リソースからインストールする
  2. xcode-select --install
    CLI のインストール
    私は既にインストールされていたためxcode-select: note: Command line tools are already installed. Use "Software Update" in System Settings or the softwareupdate command line interface to install updatesと表示されました
  3. gcc --version
Apple clang version 15.0.0 (clang-1500.0.40.1)
Target: arm64-apple-darwin23.0.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

データベース操作

name と age のカラムを持つデータベースを作成する

  1. 次のコードを記述
package main

import (
	"database/sql"
	"log"

	_ "github.com/mattn/go-sqlite3" //ビルド時にコンパイルすることでSQLにアクセス出来る
)

var DbConnection *sql.DB

func main(){
	DbConnection, _ := sql.Open("sqlite3", "./example.sql")
	defer DbConnection.Close()
	cmd := `CREATE TABLE IF NOT EXISTS person(
				name STRING,
				age INT
			)`
	//cmdを実行する
	_, err := DbConnection.Exec(cmd) //データベースの情報を反映する必要はないため、_を使用
	if err != nil{
		log.Fatalln(err)
	}
}
  1. go run main.goを実行
    example.sql というファイルができていれば ok
  2. sqlite3 example.sqlをターミナルで実行
  3. sqlite> .table
    personというテーブルが出来ていることを確認する

person テーブルに値を insert する

  1. person に対して、データを入れていく
    一旦はcmd,errを上書きする形で実行する。
    後にシングルセレクト、マルチセレクトを行いたいため別レコードを 2 つか 3 つほど入れると良いです
func main(){
	DbConnection, _ := sql.Open("sqlite3", "./example.sql")
	defer DbConnection.Close()
	cmd := `CREATE TABLE IF NOT EXISTS person(
				name STRING,
				age INT
			)`
	//cmdを実行する
	_, err := DbConnection.Exec(cmd) //データベースの情報を反映する必要はないため、_を使用
	if err != nil{
		log.Fatalln(err)
	}

	//追加
	cmd = "INSERT INTO person (name, age) VALUES (?, ?)" //SQLインジェクション対策
	_,err = DbConnection.Exec(cmd, "Finn", 30)
	if err != nil{
		log.Fatalln(err)
	}
}

https://developer.mozilla.org/ja/docs/Glossary/SQL_Injection

  1. select * from personで内容を確認
sqlite> select * from person;
Finn|30
Emma|15
Watson|40

レコードの update

先ほどとほぼ同様に行う

  1. update コマンドを記述
func main(){
	DbConnection, _ := sql.Open("sqlite3", "./example.sql")
	defer DbConnection.Close()
	cmd := `CREATE TABLE IF NOT EXISTS person(
				name STRING,
				age INT
			)`
	//cmdを実行する
	_, err := DbConnection.Exec(cmd) //データベースの情報を反映する必要はないため、_を使用
	if err != nil{
		log.Fatalln(err)
	}

	//追加
	cmd = "UPDATE person SET age = ? WHERE name = ?"
	_, err = DbConnection.Exec(cmd, 1000, "Finn")
	if err != nil{
		log.Fatalln(err)
	}
}
  1. select で確認
    1000と変更されていたので ok

マルチセレクト

  1. cmd をアップデート
func main(){
	DbConnection, _ := sql.Open("sqlite3", "./example.sql")
	defer DbConnection.Close()
	cmd := `CREATE TABLE IF NOT EXISTS person(
				name STRING,
				age INT
			)`
	//cmdを実行する
	_, err := DbConnection.Exec(cmd) //データベースの情報を反映する必要はないため、_を使用
	if err != nil{
		log.Fatalln(err)
	}

	//追加
	cmd = "SELECT * FROM person"
	rows,_ := DbConnection.Query(cmd)
	defer rows.Close()

}
  1. Person struct を作成する
type Person struct {
	Name string
	Age int
}
  1. Person スライスにデータを入れる
func main(){
	DbConnection, _ := sql.Open("sqlite3", "./example.sql")
	defer DbConnection.Close()
	cmd := `CREATE TABLE IF NOT EXISTS person(
				name STRING,
				age INT
			)`
	//cmdを実行する
	_, err := DbConnection.Exec(cmd) //データベースの情報を反映する必要はないため、_を使用
	if err != nil{
		log.Fatalln(err)
	}

	cmd = "SELECT * FROM person"
	rows,_ := DbConnection.Query(cmd)
	defer rows.Close()

	//追加
	var pp []Person
	for rows.Next(){
		var p Person
		err := rows.Scan(&p.Name, &p.Age) //アドレスを引数に渡すろstructにデータを入れてくれる
		if err != nil{
			log.Fatalln(err)
		}
		pp = append(pp,p)
	}
	for _,p := range pp {
		fmt.Println(p.Name,p.Age)
	}
}
  1. 以下のようなデータが表示されれば ok
Finn 1000
Emma 15
Watson 40

シングルセレクト

  1. cmd をアップデート
func main(){
	DbConnection, _ := sql.Open("sqlite3", "./example.sql")
	defer DbConnection.Close()
	cmd := `CREATE TABLE IF NOT EXISTS person(
				name STRING,
				age INT
			)`
	_, err := DbConnection.Exec(cmd)
	if err != nil{
		log.Fatalln(err)
	}
	//追加
	cmd = "SELECT * FROM person where age = ?"
	row := DbConnection.QueryRow(cmd, 15) //存在しているレコードのageを入力
	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)
}
  1. 実行し、確認
    レコードが表示されれば ok
Emma 15
  1. 存在しないレコードを query した場合
row := DbConnection.QueryRow(cmd, 15)
↓
row := DbConnection.QueryRow(cmd, 9999999)
  1. エラーが表示されることを確認する
    No row

レコードの削除

  1. コードを更新
func main(){
	DbConnection, _ := sql.Open("sqlite3", "./example.sql")
	defer DbConnection.Close()
	cmd := `CREATE TABLE IF NOT EXISTS person(
				name STRING,
				age INT
			)`
	_, err := DbConnection.Exec(cmd)
	if err != nil{
		log.Fatalln(err)
	}
	//追加
	cmd = "DELETE FROM person WHERE name = ?"
	DbConnection.Exec(cmd, "Finn")
	if err != nil{
		log.Fatalln(err)
	}
}
  1. 対象が消えていれば ok

Discussion