Using standard database/sql Row.Scan()
I have a problem with null values in the row. Without considering possible null values in a row, I can get scan errors like <nil> -> *string
. This is quite common using LEFT JOIN queries or weak defined tables missing NO NULL column constraints.
There are sql.NullXXX
types (e.g. sql.NullInt64) which can be used to scan possible null value from a row, and then check if the value is .Valid
. However, these types don’t implement JSON marshalling, and those more logic and coding is required.
To solve this, is it better approach to COALESCE()
column values in SQL query or do some extra coding in golang code?
You can use aliases for types provided by sql package such as (NullInt64, NullString etc...). There are two advantages of using that, one you can scan null values and can get in golang structure and second you can marshal that struct in JSON.
NullString is a way to represent null string coming from SQL (which correspond to "NULL"). On the other hand, a nil *string is a pointer to a string which is nil, so the two are different.
NULL is used in SQL to indicate that a value doesn't exist in the database. It's not to be confused with an empty string or a zero value. While NULL indicates the absence of a value, the empty string and zero both represent actual values.
// String is a nullable string. It supports SQL and JSON serialization.
You can use aliases for types provided by sql package such as (NullInt64, NullString etc...). There are two advantages of using that, one you can scan null values and can get in golang structure and second you can marshal that struct in JSON.
Please, look at the sample code:
// NullInt64 is an alias for sql.NullInt64 data type
type NullInt64 sql.NullInt64
// Scan implements the Scanner interface for NullInt64
func (ni *NullInt64) Scan(value interface{}) error {
var i sql.NullInt64
if err := i.Scan(value); err != nil {
return err
}
// if nil the make Valid false
if reflect.TypeOf(value) == nil {
*ni = NullInt64{i.Int64, false}
} else {
*ni = NullInt64{i.Int64, true}
}
return nil
}
// MarshalJSON for NullInt64
func (ni *NullInt64) MarshalJSON() ([]byte, error) {
if !ni.Valid {
return []byte("null"), nil
}
return json.Marshal(ni.Int64)
}
Please, have a look at this article, it would be very helpful about handling null values in golang and how to use it in JSON.
As an option you can implement your custom data type that would match the JSON Marshaler interface. After that you would be able to marshal your struct using regular tags.
Check the example:
type UserTitleType sql.NullString
func (s UserTitleType) MarshalJSON() ([]byte, error) {
if s.Valid {
return json.Marshal(s.String)
}
return jsonNull, nil
}
type User struct {
Id int64 `json:"id"`
Title UserTitleType `json:"title"`
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With