我需要更新bulk
中的数据,这些数据中的一些字段经过二次处理后具有become different
。比如
[{"ID":83,"ip":"10.215.14.216","test1":24,"test2":126,"test3":300},
{"ID":82,"ip":"10.215.14.215","test1":6,"test2":100,"test3":600}
...]
正式的gorm批处理更新是将一些字段更改为same value
。
使用loop to update one at a time
最简单的方法,但个人感觉inefficient
。
for _,v := range bulkdata{
// update single
}
是否有一种提高效率的批量更新方法?我真的很感激你在这方面的帮助。
发布于 2022-09-14 07:20:35
case when
这样的UPDATE table_name
SET ip = CASE id
WHEN 83 THEN '10.215.14.216'
WHEN 82 THEN '10.215.14.215'
END, test1 = CASE id
WHEN 83 THEN 24,
WHEN 82 THEN 6
END
WHERE id IN (83, 82)
reflect
package main
import (
"bytes"
"fmt"
"math"
"reflect"
"strconv"
"strings"
)
func genBatchUpdateSQL(tableName string, dataList interface{}) ([]string, error) {
fieldValue := reflect.ValueOf(dataList)
fieldType := reflect.TypeOf(dataList).Elem().Elem()
sliceLength := fieldValue.Len()
fieldNum := fieldType.NumField()
// TODO add validate struct. struct must have primaryKey and gorm tag
var IDList []string
updateMap := make(map[string][]string)
for i := 0; i < sliceLength; i++ {
structValue := fieldValue.Index(i).Elem()
for j := 0; j < fieldNum; j++ {
elem := structValue.Field(j)
var tid string
switch elem.Kind() {
case reflect.Int64:
tid = strconv.FormatInt(elem.Int(), 10)
case reflect.String:
if strings.Contains(elem.String(), "'") {
tid = fmt.Sprintf("'%v'", strings.ReplaceAll(elem.String(), "'", "\\'"))
} else {
tid = fmt.Sprintf("'%v'", elem.String())
}
case reflect.Float64:
tid = strconv.FormatFloat(elem.Float(), 'f', -1, 64)
case reflect.Bool:
tid = strconv.FormatBool(elem.Bool())
default:
return nil, fmt.Errorf("type conversion error, param is %v", fieldType.Field(j).Tag.Get("json"))
}
gormTag := fieldType.Field(j).Tag.Get("gorm")
fieldTag := getFieldName(gormTag)
if strings.HasPrefix(fieldTag, "id;") {
id, err := strconv.ParseInt(tid, 10, 64)
if err != nil {
return nil, err
}
if id < 1 {
return nil, fmt.Errorf("this structure should have a primary key and gt 0")
}
IDList = append(IDList, tid)
continue
}
valueList := append(updateMap[fieldTag], tid)
updateMap[fieldTag] = valueList
}
}
length := len(IDList)
// Length of each batch submission
size := 200
SQLQuantity := getSQLQuantity(length, size)
var SQLArray []string
k := 0
for i := 0; i < SQLQuantity; i++ {
count := 0
var record bytes.Buffer
record.WriteString("UPDATE " + tableName + " SET ")
for fieldName, fieldValueList := range updateMap {
record.WriteString(fieldName)
record.WriteString(" = CASE " + "id")
for j := k; j < len(IDList) && j < len(fieldValueList) && j < size+k; j++ {
record.WriteString(" WHEN " + IDList[j] + " THEN " + fieldValueList[j])
}
count++
if count != fieldNum-1 {
record.WriteString(" END, ")
}
}
record.WriteString(" END WHERE ")
record.WriteString("id" + " IN (")
min := size + k
if len(IDList) < min {
min = len(IDList)
}
record.WriteString(strings.Join(IDList[k:min], ","))
record.WriteString(");")
k += size
SQLArray = append(SQLArray, record.String())
}
return SQLArray, nil
}
func getSQLQuantity(length, size int) int {
return int(math.Ceil(float64(length) / float64(size)))
}
func getFieldName(fieldTag string) string {
fieldTagArr := strings.Split(fieldTag, ":")
if len(fieldTagArr) == 0 {
return ""
}
return fieldTagArr[len(fieldTagArr)-1]
}
type Ts struct {
ID int64 `gorm:"column:id;primaryKey" json:"id"`
IP string `gorm:"column:ip" json:"ip"`
Test1 float64 `gorm:"column:test1" json:"test1"`
}
func main() {
var t []*Ts
demo1 := &Ts{1, "11.215.14.216", 11.0}
demo2 := &Ts{2, "12.215.14.216", 12.0}
demo3 := &Ts{3, "13.215.14.216", 13.0}
demo4 := &Ts{4, "14.215.14.216", 14.0}
demo5 := &Ts{5, "15.215.14.216", 15.0}
t = append(t, demo1, demo2, demo3, demo4, demo5)
res, err := genBatchUpdateSQL("table_name", t)
if err != nil {
return
}
fmt.Println(res)
// [UPDATE table_name SET ip = CASE id WHEN 1 THEN 'Test001' WHEN 2 THEN 'Test002' WHEN 3 THEN 'Test003' WHEN 4 THEN 'Test004' WHEN 5 THEN 'Test005' END, test1 = CASE id WHEN 1 THEN 11 WHEN 2 THEN 12 WHEN 3 THEN 13 WHEN 4 THEN 14 WHEN 5 THEN 15 END WHERE id IN (1,2,3,4,5);]
}
https://stackoverflow.com/questions/73702535
复制相似问题