Golang GORMでよく使うSQLの書き方


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

Create

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

// Create
db.Create(&models.User{Name: "user"})

実行SQL

// Create
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

1カラムだけアップデートします。

// Create
user := &models.User{Name: "user"}
db.Create(user)

// Update
db.Model(user).Update("name", "user2")

実行SQL

// Create
INSERT INTO "users" ("created_at","updated_at","name","email") VALUES ('2020-04-25 11:34:39','2020-04-25 11:34:39','user','');

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

Updates

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

// Create
user := &models.User{Name: "user"}
db.Create(user)

// Updates
db.Model(user).Updates(map[string]interface{}{
        "name": "user3", 
        "email": "g5.taisa831@gmail.com",
    }
)

実行SQL

// Create
INSERT INTO "users" ("created_at","updated_at","name","email") VALUES ('2020-04-25 11:39:52','2020-04-25 11:39:52','user','');

// Updates
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 を実行する際にすべてのフィールドを含みます。フィールドを指定しなくても空にはなりません。また、レコードが存在しない場合は insert になります(実質 FirstOrCreate の振る舞いとなる)

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

// Save
user.Name = "user2" 
db.Save(user)

実行SQL

// Create 
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'); 

// Save 
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;

Read

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

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

// First
db.First(user, "name = ?", "user")

// Where句付きFirst
db.Where("name = ?", "user").First(user)

実行SQL

// Create
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') 

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

// Where句付きFirst
SELECT * FROM "users" WHERE "users"."id" = 10 AND ((name = 'user')) ORDER BY "users"."id" ASC LIMIT 1

Join

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

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

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

// Join user, post
var users []models.User 
db.Table("users").
    Select("users.*, posts.*").
    Joins("inner join posts on users.id = posts.user_id").
    Find(&users)

実行SQL

// Create user
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') 

// Create post
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')

// Join user, post
SELECT users.*, posts.* FROM "users" INNER JOIN posts ON users.id = posts.user_id;

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
}

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

実行SQL

// Preload
SELECT * FROM "users" WHERE "users"."id" = 16;
SELECT * FROM "posts" WHERE ("user_id" IN (16));

参考


関連記事