taisablog

taisa's engineer blog

Go

GORMでよく使うSQLの書き方

投稿日:


GORMでよく使うSQLの書き方をメモとして残しておきます。詳細は記事最後の参考リンクの公式ドキュメントで確認できます。

CREATE

insertするだけであれば create を利用します。

db.Create(&models.User{Name: "user"})
# 実行SQL
INSERT INTO "users" ("created_at","updated_at","name","email") VALUES ('2020-04-25 11:22:00','2020-04-25 11:22:00','user',0)

UPDATE

特定のフィールドだけ更新したい場合、 Update と Updates を使います。

update

一つのフィールドだけアップデートします。

user := &models.User{Name: "user"}
db.Create(user)
db.Model(user).Update("name", "user2")
# 実行SQL
INSERT INTO "users" ("created_at","updated_at","name","email") VALUES ('2020-04-25 11:34:39','2020-04-25 11:34:39','user','')

UPDATE "users" SET "name" = 'user2', "updated_at" = '2020-04-25 11:34:39'  WHERE "users"."id" = 5

updates

updates は map を利用して複数のフィールドをアップデートします。

user := &models.User{Name: "user"}
db.Create(user)
db.Model(user).Updates(map[string]interface{}{"name": "user3", "email": "g5.taisa831@gmail.com"})
# 実行SQL
INSERT INTO "users" ("created_at","updated_at","name","email") VALUES ('2020-04-25 11:39:52','2020-04-25 11:39:52','user','')

UPDATE "users" SET "email" = 'g5.taisa831@gmail.com', "name" = 'user3', "updated_at" = '2020-04-25 11:39:52'  WHERE "users"."id" = 6

SAVE

Save は SQL を実行する際にすべてのフィールドを含みます。フィールドを指定しなくても空にはなりません。

user := &models.User{Name: "user", Email: "g5.taisa831@gmail.com"}
db.Create(user)

user.Name = "user2"
db.Save(user)
# 実行SQL
INSERT INTO "users" ("created_at","updated_at","name","email") VALUES ('2020-04-25 11:43:30','2020-04-25 11:43:30','user','g5.taisa831@gmail.com')

UPDATE "users" SET "created_at" = '2020-04-25 11:43:30', "updated_at" = '2020-04-25 11:43:30', "name" = 'user2', "email" = 'g5.taisa831@gmail.com'  WHERE "users"."id" = 8 

Assign FirstOrCreate

create or update を利用するには AssignFirstOrCreate を利用します。

レコードが存在しない場合

user := &models.User{}
db.Where("name = ?", "non user").Assign(models.User{Name: "user"}).FirstOrCreate(&user)
# 実行SQL
SELECT * FROM "users"  WHERE (name = 'non user') ORDER BY "users"."id" ASC LIMIT 1

INSERT INTO "users" ("created_at","updated_at","name","email") VALUES ('2020-04-25 12:04:24','2020-04-25 12:04:24','user','') 

レコードが存在する場合

user := &models.User{}
db.Where("name = ?", "user").Assign(models.User{Name: "user2"}).FirstOrCreate(user)
# 実行SQL
SELECT * FROM "users"  WHERE (name = 'user') ORDER BY "users"."id" ASC LIMIT 1

UPDATE "users" SET "name" = 'user2', "updated_at" = '2020-04-25 12:05:45'  WHERE "users"."id" = 3 AND ((name = 'user'))

READ

1レコードだけ取得するにはFirstを利用します。

user := &models.User{Name: "user", Email: "g5.taisa831@gmail.com"}
db.Create(user)

db.First(user, "name = ?", "user")
db.Where("name = ?", "user").First(user)
# 実行SQL
INSERT INTO "users" ("created_at","updated_at","name","email") VALUES ('2020-04-25 11:48:25','2020-04-25 11:48:25','user','g5.taisa831@gmail.com') 

SELECT * FROM "users"  WHERE "users"."id" = 10 AND ((name = 'user')) ORDER BY "users"."id" ASC LIMIT 1

SELECT * FROM "users"  WHERE "users"."id" = 10 AND ((name = 'user')) ORDER BY "users"."id" ASC LIMIT 1 

JOIN

joinのサンプルは下記となります。

user := &models.User{Name: "user", Email: "g5.taisa831@gmail.com"}
db.Create(user)

post := &models.Post{
		Post:      "post",
		UserId:    user.ID,
	}
db.Create(post)

var users []models.User
db.Table("users").Select("users.*, posts.*").Joins("inner join posts on users.id = posts.user_id").Find(&users)
# 実行SQL
INSERT INTO "users" ("created_at","updated_at","name","email") VALUES ('2020-04-25 12:26:39','2020-04-25 12:26:39','user','g5.taisa831@gmail.com')

INSERT INTO "posts" ("created_at","updated_at","user_id","post") VALUES ('2020-04-25 12:26:39','2020-04-25 12:26:39',14,'post')

SELECT users.*, posts.* FROM "users" inner join posts on users.id = posts.user_id 

> user

PRELOAD

UserモデルにPostsを追加すると PRELOAD が利用できます。PRELOAD を利用すると JOIN せずに関連レコードを取得することができます。下記のようなJSONを返したいときに便利です。

users {
	"id": "1",
        "name": "user",
	"posts" [
		{},
		{},
		{},
		{},
	]
}
type User struct {
	ID        uint `gorm:"primary_key"`
	CreatedAt time.Time
	UpdatedAt time.Time
	Posts     Post
	Name      string
	Email     string
}

type Post struct {
	ID        uint `gorm:"primary_key"`
	CreatedAt time.Time
	UpdatedAt time.Time
	UserId    uint
	Post      string
}

user := &models.User{Name: "user", Email: "g5.taisa831@gmail.com"}
db.Preload("Posts").Find(&user)
# 実行SQL
SELECT * FROM "users"  WHERE "users"."id" = 16 

SELECT * FROM "posts"  WHERE ("user_id" IN (16))

参考

-Go

執筆者:


  1. Mathias says:

    Anyway just wanted to say thanks for your website. Stuff like
    this allow me to stay on track and helps keep me. I am hoping that you
    continue to develop, along with can discover it! Good luck and thanks again.
    Anyway, I really like keto up to now, although I’m experimenting with trying to set my own spin on it.

    It’s important to be flexible with your diet, even if you’re locked into
    something like”keeping carbohydrates low”. I want to lose weight, however I don’t want to
    be the individual eating out that orders something odd off the menu, or even nothing
    at all. If your daily diet comes at the cost of your happiness,
    if you ask me it’s just flat out not worth it. xoxo That is GREAT.
    Been doing my very best to attempt to do quality research,
    so things like this really helps. Anyone else think that
    the biggest issue people have with weight loss comes from them not putting in the work ?

    You have to be inclined to do a bit of research first, although
    you want to begin losing weight ASAP like I do.
    I’m sorry to say you are just going to have issues if you do
    not do your part.

comment

Your email address will not be published.

関連記事

Go言語 ORMライブラリ GORMの使い方

Go言語 ORMライブラリのGORMの簡単な使い方を確認してみました。また、公式ドキュメントにしっかりと使い方が書いてありますので基本的にはそちらを参考にしてもらえればと思います(すべてではないですが日本語訳もされています)。その上でクイックスタートを元に簡単な使い方と挙動を確認してみます。 http://gorm.io/ja_JP/docs/ インストール 以下のコマンドでインストールできます。 go get -u github.com/jinzhu/gorm クイックスタート 公式ドキュメントにあるクイックスタートを実行してみました。DBだけsqliteではなくmysqlに変更しています。 package main import ( “github.com/jinzhu/gorm” // _ “github.com/jinzhu/gorm/dialects/sqlite” _ “github.com/jinzhu/gorm/dialects/mysql” ) type Product struct { gorm.Model Code string Price uint } func main() { // db, err := gorm.Open(“sqlite3”, “test.db”) db, err := gorm.Open(“mysql”, “gorm:gorm@/sandbox?charset=utf8mb4&parseTime=True&loc=Local”) if err != nil { panic(“データベースへの接続に失敗しました”) } defer db.Close() // スキーマのマイグレーション db.AutoMigrate(&Product{}) // Create db.Create(&Product{Code: “L1212”, Price: 1000}) // Read var product Product db.First(&product, 1) // idが1の製品を探します db.First(&product, “code = ?”, “L1212”) // codeがL1212の製品を探します // Update – 製品価格を2,000に更新します db.Model(&product).Update(“Price”, 2000) // Delete – 製品を削除します db.Delete(&product) } 実行してみるとproductsテーブルが作成され、以下のカラムとレコードができました。structでは宣言していない、id、created_at、updated_at、deleted_atカラムができ、deleted_atに日付が入りソフトデリートが行われています。 go run main.go gorm.Model gorm.Modelを宣言するとid、created_at、updated_at、deleted_atカラムが自動的に注入されます。また,deleted_atカラムがある場合、Deleteはソフトデリートになります。 参考: http://gorm.io/ja_JP/docs/conventions.html …

no image

DockerでGoのWebサーバーを起動する

ミニマムにやっておかないと忘れがちなのでメモ サンプル用Goサーバを作成する package main import ( “encoding/json” “net/http” ) type User struct { FirstName string `json:”firstName”` LastName string `json:”lastName”` } func users(w http.ResponseWriter, req *http.Request) { w.Header().Set(“Content-Type”, “application/json”) user := User{ FirstName: “John”, LastName: “Doe”, } var users []User users = append(users, user) json.NewEncoder(w).Encode(users) } func main() { http.HandleFunc(“/users”, users) http.ListenAndServe(“:8002”, nil) } 普通に起動して動作確認をします。 $ go run main.go http://localhost:8002/usersにアクセスするとJSON結果が出力されます。 [ { “firstName”: “John”, “lastName”: “Doe” } ] Dockerfile Dockerfileを作成します。alpineをつけるとよりミニマムなイメージができます。参考(https://hub.docker.com/_/golang?tab=description) FROM golang:1.14 #FROM golang:1.14-alpine # コンテナログイン時のディレクトリ指定 WORKDIR /opt/sandbox-docker-go # ホストのファイルをコンテナの作業ディレクトリにコピー COPY . . # ADD . . # ビルド RUN go build -o app main.go # 起動 CMD [“/opt/sandbox-docker-go/app”] 構成 $ …

Go言語 GORM+GinでTODOリストのAPIを作ってみた

前回の「Go言語 GORM+GinでTODOリストを作ってみた」に続いて「GORM+Gin」でTODOリストのAPIを作ってみました。ソースコードは前回からの差分だけを記載しています。できたものは下記URLから確認できます。 http://sandbox.taisablog.com/api/v1/ GinのGithub 事前情報 Webフレームワーク:Gin (https://github.com/gin-gonic/gin) ORM:GORM (https://gorm.io/docs) DB:MySQL ルーティングは今回はAPIなので以下としました。モデルをtasksにすればよかったと思いましたが一旦このままにしておきます。 [GIN-debug] GET /todo –> main.main.func1 (3 handlers) // 一覧表示 [GIN-debug] POST /todo –> main.main.func2 (3 handlers) // 新規作成 [GIN-debug] GET /todo/:id –> main.main.func3 (3 handlers) // 編集画面表示 [GIN-debug] PUT /todo/:id –> main.main.func4 (3 handlers) // 編集 [GIN-debug] DELETE /todo/:id –> main.main.func5 (3 handlers) // 削除 ディレクトリ構成 . ├── api │   └── v1 │   └── todo.go ├── controllers │   └── todo.go ├── db │   └── db.go ├── main.go ├── models │   └── todo.go ├── router    └── router.go router.go router.goにr.Group(“/api/v1”)のAPI用のグループを追加してルーティングを追加しました。 package router import ( “github.com/gin-contrib/cors” “github.com/gin-gonic/gin” “github.com/jinzhu/gorm” v1 “github.com/taisa831/sandbox-gin/api/v1” “github.com/taisa831/sandbox-gin/controllers” …

[Golang]Goのio/ioutilパッケージは分かりやすくて使いやすい

Goのioパッケージは主にインターフェースになっていて他のパッケージで多く実装されています。またioパッケージにもパブリックな関数がありファイルの入出力はできますが少し細かい処理になります。io/ioutilパッケージを使うとファイルの入出力処理が簡単にできます。以下にio/ioutilパッケージを使った処理とそれに対するテストコードを記載します。 io/ioutil/ioutil.go ReadAll() func ReadAll() string { file, _ := os.Open(“testdata/src.txt”) b, _ := ioutil.ReadAll(file) return string(b) } ReadAllテスト func TestReadAll(t *testing.T) { str := ReadAll() if str != “0123456789” { t.Errorf(“TestReadAll Error. %s”, str) } } ReadFile() func ReadFile() string { b, _ := ioutil.ReadFile(“testdata/src.txt”) return string(b) } ReadFileテスト func TestReadFile(t *testing.T) { str := ReadFile() if str != “0123456789” { t.Errorf(“TestReadAll Error. %s”, str) } } WriteFile() func WriteFile() string { b := []byte(“0123456789”) _ = ioutil.WriteFile(“testdata/dst.txt”, b, os.ModePerm) b, _ = ioutil.ReadFile(“testdata/dst.txt”) return string(b) } WriteFileテスト func TestWriteFile(t *testing.T) { str := WriteFile() if str != “0123456789” …

no image

【3分で作れる】Goのコマンドラインツール by Cobra

同僚のおすすめでコマンドラインツール作成にCobraを使いました。ものすごく簡単につくれるのですが、それでも少しハマったところがあったので、コマンドラインツールを作るまでの流れを書いておきます。 前提 go version go1.14.2 darwin/amd64利用ライブラリ:https://github.com/spf13/cobra本記事のサンプルコード:https://github.com/taisa831/sandbox-cobra Index 雛形を作成するコマンドを追加するコンフィグを追加するサブコマンドを追加するまとめ 雛形を作成する 雛形作成にはgeneratorを使います。go getしてcobraコマンドを利用可能にします。 go get -u github.com/spf13/cobra/cobra cobraコマンドを実行すると以下のようなusageが表示されます。 $ cobra Cobra is a CLI library for Go that empowers applications. This application is a tool to generate the needed files to quickly create a Cobra application. Usage: cobra [command] Available Commands: add Add a command to a Cobra Application help Help about any command init Initialize a Cobra Application Flags: -a, –author string author name for copyright attribution (default “YOUR NAME”) –config string config file (default is $HOME/.cobra.yaml) -h, –help help for cobra -l, –license string name of license for the project …