Golang 빈 문자열 대신 SQL에 NULL 삽입
나는 골랑을 사용하여 mysql 데이터베이스에 데이터를 삽입하려고 합니다.내 값이 빈 문자열을 차지하는 경우, 나는 null을 삽입하고 싶습니다.빈 문자열 대신 null을 삽입하도록 다음을 조정하려면 어떻게 해야 합니다.감사해요.
_, err := m.Db.Exec(`INSERT INTO
visitor_events
(type,
info,
url_path,
visitor_id,
created_at,
domain)
VALUES
(?, ?, ?, ?, ?, ?)`,
m.SaveEventType(ve), ve.EventInfo, m.SaveURLPath(ve.UrlPath), ve.VisitorId, time.Now().UTC(), ve.Domain)
내 코드에서 나는 문자열을 다음으로 변환하는 함수를 가지고 있습니다.
func NewNullString(s string) sql.NullString {
if len(s) == 0 {
return sql.NullString{}
}
return sql.NullString{
String: s,
Valid: true,
}
}
그럼 제가 사용할 때마다Exec
DB에서 NULL일 수 있는 문자열을 다음과 같이 래핑합니다.NewNullString
기능.
db.Exec(`
insert into
users first_name, last_name, email
values (?,?,?)`,
firstName,
lastName,
NewNullString(email),
)
그database/sql
패키지에 다음과 같습니다.NullString
이 상황에 대해 type(입력하세요.
기본적으로 그냥 사용합니다.sql.NullString
DB에서 null로 설정할 문자열 대신.
사용할 수도 있습니다.*string
당신의 코드에서 같은 취지로.
두 경우 모두 null 가능 문자열에서 null이 아닌 문자열로 매핑하는 데 문제가 있습니다.빈 문자열은 기술적으로 값이므로 빈 문자열을 0으로 변환해야 한다면 거의 항상 다음과 같은 작업을 수행해야 합니다.
nullableS := &s
if s == "" {
nullableS = nil
}
다른 대안은 그냥 사용하는 것입니다.*string
대신에string
앱 전체에 걸쳐 모델에서 사용할 수 있습니다.
데이터베이스에서 저는 빈 문자열과 null이 동일하다는 접근 방식을 취해 왔으며, 빈 문자열을 DB에 저장하고 대부분의 열을 null로 만들 수 없습니다.
사용할 수도 있습니다.NULLIF
SQL 쿼리의 함수입니다.
NULLIF(?, '')
빈 문자열을 삽입하려고 하면 빈 문자열 대신 NULL을 반환합니다.
NULLIF에 대해 자세히 알아보기: 링크
N개의 NewNullType 함수를 만들지 않으려면 Value() 함수와 함께 pgx & pgtype을 사용하는 것이 좋습니다.
https://github.com/jackc/pgtype
https://github.com/jackc/pgtype/blob/master/text.go
예제(테스트되지 않음)
type User struct {
email pgtype.Text `json:"email"`
firstName pgtype.Text `json:"first_name"`
}
func InsertUser(u User) error {
// --> get SQL values from u
var err error
email, err := u.email.Value() // see https://github.com/jackc/pgtype/blob/4db2a33562c6d2d38da9dbe9b8e29f2d4487cc5b/text.go#L174
if err != nil {
return err
}
firstName, err := d.firstName.Value()
if err != nil {
return err
}
// ...
sql := `INSERT INTO users (email, first_name) VALUES ($1, $2)`
conn, err := pgx.Connect(ctx, "DATABASE_URL")
defer conn.Close(ctx)
tx, err := conn.Begin()
defer tx.Rollback(ctx)
// --> exec your query using the SQL values your get earlier
_, err = tx.Exec(ctx, sql, email, firstName)
// handle error
}
err = tx.Commit(ctx)
// handle error
return nil
}
예: NULL 값 추가:
/*Exaples:
ParamReplacingMode = 0 // no replacing params
isql:=InitSql(db,"SELECT * FROM table WHERE price+vat>:Sum and country=:C") // by Oracle
AddParam(isql,":C", "USA") // the order for AddParams is not bound, you can add params any order
AddParam(isql,":Sum", 130.5)
res,err:= SqlQuery(isql) //result: db.Query("SELECT * FROM table WHERE price+vat>:Sum and country=:C", 130.5,"USA")
or
ParamReplacingMode = 1 // MySQL - replacing params to "?"
isql:=InitSql(db,"SELECT * FROM table WHERE price+vat>:Sum and country=:C") // by Oracle convert to Mysql
AddParam(isql,":C", "USA") // the order for AddParams is not bound, you can add params any order
AddParam(isql,":Sum", 130.5)
res,err:= SqlQuery(isql) //result: db.Query("SELECT * FROM table WHERE price+vat>? and country=?", 130.5,"USA") //replacing params to "?"
or
ParamReplacingMode = 0 //no replacing params
isql:=InitSql(db,"SELECT * FROM table WHERE price+vat>$1 and country=$2") // by Postgre
AddParam(isql,"$1", 130.5)
AddParam(isql,"$2", "USA") // the order for AddParams is not bound, you can add params any order
res,err:= SqlQuery(isql) //result: db.Query("SELECT * FROM table WHERE price+vat>$1 and country=$2", 130.5,"USA")
or
ParamReplacingMode = 2 // mode Oracle to Postgre, replacing params to <$Number>
isql:=InitSql(db,"SELECT * FROM table WHERE price+vat>:Sum and country=:C") // by Oracle convert to Postgre
AddParam(isql,":C","USA")
AddParam(isql,":Sum",130.5)
res,err:= SqlQuery(isql) //result: db.Query("SELECT * FROM table WHERE price+vat>$1 and country=$2", 130.5,"USA")
SqlExec() is similar as SqlQuery(), but call db.Exec(...)
Example , add NULL value:
isql:=InitSql(db,"INSERT INTO table (id, name) VALUES (:ID,:Name)")
AddParam(isql, ":ID", 1)
AddParam(isql, ":Name", nil)
res,err:= SqlExec(isql)
*/
type (
TisqlMode int32
TisqlAt struct {
ParamName string
Pos int
ParamVal any
}
Tisql struct {
Sql string
ResultSql string
DB *sql.DB
Params map[string]any
At []TisqlAt
}
)
const (
Oracle TisqlMode = iota //0, no replacing params
Mysql //1, "SELECT * FROM table WHERE price+vat>:Sum and country=:C" -> db.Query("SELECT * FROM table WHERE price+vat>? and country=?", 130.5,"USA")
Postgre //2, "SELECT * FROM table WHERE price+vat>:Sum and country=:C" -> db.Query("SELECT * FROM table WHERE price+vat>$1 and country=$2", 130.5,"USA")
)
func (s TisqlMode) String() string {
switch s {
case Oracle:
return "Oracle" // no replacing params
case Mysql:
return "Mysql"
case Postgre:
return "Postgre"
}
return "unknown"
}
var ParamReplacingMode TisqlMode = -1 //-1 = unknown, 0 = no replacing params, 1 = to MySql, 2 = to Postgre
func indexAt(pStr, pSubStr string, pos int) int { //Index from position
if pos >= len(pStr) {
return -1
}
if pos < 0 {
pos = 0
}
idx := strings.Index(pStr[pos:], pSubStr)
if idx > -1 {
idx += pos
}
return idx
}
func InitSql(db *sql.DB, sql string) *Tisql {
if ParamReplacingMode < 0 { // unknow
_, err := db.Exec("?")
if err != nil {
s := strings.ToLower(fmt.Sprint(err))
if indexAt(s, "mysql", 0) > 0 {
ParamReplacingMode = 1
} else {
ParamReplacingMode = 0
}
}
}
var isql Tisql
isql.Sql = sql
isql.DB = db
isql.Params = make(map[string]any)
return &isql
}
func AddParam(isql *Tisql, pParam string, pValue any) {
isql.Params[pParam] = pValue
}
func paramOrder(isql *Tisql, pCheckParamCount bool) error {
var at TisqlAt
isql.ResultSql = isql.Sql
t := ""
b := strings.ToLower(isql.Sql) + " "
mMode := ParamReplacingMode
var p, p1, p2 int
for name, v := range isql.Params {
p1 = 0
for p1 >= 0 {
p = indexAt(b, strings.ToLower(name), p1)
if p < 0 {
p1 = -1
continue
} else {
p2 = p + len(name)
t = b[p2 : p2+1] //char after param
if indexAt(" :,;!?%$<>^*+-/()[]{}=|'`\"\r\n\t", t, 0) < 0 {
p1 = p + 1
continue
}
p1 = -1
}
}
if p >= 0 {
at.Pos = p
at.ParamVal = v
at.ParamName = name
isql.At = append(isql.At, at)
}
}
if pCheckParamCount && len(isql.At) != len(isql.Params) {
return fmt.Errorf("Different count of params %d / %d", len(isql.At), len(isql.Params))
}
if len(isql.At) > 1 {
sort.Slice(isql.At,
func(i, j int) bool {
return isql.At[i].Pos < isql.At[j].Pos
})
}
mLen := len(isql.Sql)
switch mMode {
case 1: //to Mysql
{
p1, p2, s := 0, 0, ""
for _, at := range isql.At {
p2 = at.Pos
if p2 >= 0 && p2 <= mLen {
if p2 > p1 {
s += isql.Sql[p1:p2] + "?"
}
p1 = p2 + len(at.ParamName)
}
}
if p1 < len(isql.Sql) {
s += isql.Sql[p1:len(isql.Sql)]
}
isql.ResultSql = s
}
case 2: //to Postgre
{
p1, p2, s := 0, 0, ""
for i, at := range isql.At {
p2 = at.Pos
if p2 >= 0 && p2 <= mLen {
if p2 > p1 {
s += isql.Sql[p1:p2] + "$" + fmt.Sprint(i+1)
}
p1 = p2 + len(at.ParamName)
}
}
if p1 < len(isql.Sql) {
s += isql.Sql[p1:len(isql.Sql)]
}
isql.ResultSql = s
}
}
return nil
}
func ParamsStr(isql *Tisql) string {
s := ""
for i, at := range isql.At {
s += "[" + fmt.Sprint(i+1) + ". " + at.ParamName + "=\"" + fmt.Sprint(at.ParamVal) + "\"]"
}
return s
}
func SqlStr(isql *Tisql) string {
s := "SQL:[" + isql.ResultSql + "]"
if len(isql.At) > 0 {
s += " Params:" + ParamsStr(isql)
}
return s
}
func SqlExec(isql *Tisql, opt ...bool) (sql.Result, error) {
checkParamCount := false
if len(opt) > 0 {
checkParamCount = opt[0]
}
err := paramOrder(isql, checkParamCount)
if err != nil {
return nil, err
}
mLen := len(isql.At)
mVal := make([]any, mLen)
for i := range mVal {
mVal[i] = isql.At[i].ParamVal
}
return isql.DB.Exec(isql.ResultSql, mVal...)
}
func SqlQuery(isql *Tisql, opt ...bool) (*sql.Rows, error) {
checkParamCount := false
if len(opt) > 0 {
checkParamCount = opt[0]
}
err := paramOrder(isql, checkParamCount)
if err != nil {
return nil, err
}
mLen := len(isql.At)
mVal := make([]any, mLen)
for i := range mVal {
mVal[i] = isql.At[i].ParamVal
}
return isql.DB.Query(isql.ResultSql, mVal...)
}
언급URL : https://stackoverflow.com/questions/40266633/golang-insert-null-into-sql-instead-of-empty-string
'source' 카테고리의 다른 글
한 해의 매월 레코드 수 (0) | 2023.07.29 |
---|---|
동적 열이 있는 MySQL 피벗 테이블 쿼리 (0) | 2023.07.29 |
URL에서 호스트 도메인을 가져오시겠습니까? (0) | 2023.07.29 |
Oracle - 참조자에서 특정 열 선택 (0) | 2023.07.29 |
도커 컨테이너 내에서 호스팅되는 phpmyadmin을 통해 MariaDB 데이터베이스에 액세스하려고 합니다. (0) | 2023.07.24 |