🫥

GORMの Pluck で converting NULL to int is unsupported がでたときの対応

2024/08/01に公開

Go言語のORMであるGORMでは、selectで複数のレコードを取得する際、任意のカラムだけを取得する方法として、Pluckが使えます。
https://gorm.io/ja_JP/docs/advanced_query.html

例えば、このようにすると、Userの中の idカラムだけを int64のスライスにセットすることができてとても便利です。

// Retrieving ages of all users
var ids []int64
db.Model(&User{}).Pluck("id", &ids)

先日、以下のようなコードを書いて実行したところ、、、

    var userIDs []int
        result := db.Table("teams").
            Joins("LEFT JOIN managers ON managers.team_id = teams.id").
            Pluck("managers.user_id", &userIDs)
    if result.Error != nil {
        log.Fatal(result.Error)
    }

sql: Scan error on column index 0, name "user_id": converting NULL to int is unsupported というエラーが出ました。

これは、取得した結果、user_idカラムがNULLのレコードがあり、int に変換できなかった、ということになります。

対策方法1. LEFT JOIN をやめる。
LEFT JOIN の場合、右側のテーブルに一致するレコードがない場合、NULLが返ってきてしまいます。以下のように、INNER JOIN を使うと、完全に一致するレコードのみ取得されるので、NULLにならないようになります。

    var userIDs []int
    result := db.Table("teams").
-       Joins("LEFT JOIN managers ON managers.team_id = teams.id").
+       Joins("INNER JOIN managers ON managers.team_id = teams.id").
        Pluck("managers.user_id", &userIDs)

対策方法2. NULLを変換する。
外部結合にする必要がある場合や、そもそもNULLが許可されたカラムの場合、 MySQLの場合は IFNULL などを使って、NULLを変換することで回避できます。以下のコードでは、NULLの場合に -1 が返ってきます。

    var userIDs []int
    result := db.Table("teams").
        Joins("LEFT JOIN managers ON managers.team_id = teams.id").
-       Pluck("managers.user_id", &userIDs)
+       Pluck("IFNULL(managers.user_id, -1)", &userIDs)
    if result.Error != nil {
        log.Fatal(result.Error)
    }

Discussion