首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用gorm批量更新数据

使用gorm批量更新数据
EN

Stack Overflow用户
提问于 2022-09-13 11:52:13
回答 1查看 638关注 0票数 1

我需要更新bulk中的数据,这些数据中的一些字段经过二次处理后具有become different。比如

代码语言:javascript
运行
复制
[{"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

代码语言:javascript
运行
复制
for _,v := range bulkdata{
  // update single
}

是否有一种提高效率的批量更新方法?我真的很感激你在这方面的帮助。

EN

回答 1

Stack Overflow用户

发布于 2022-09-14 07:20:35

  1. 尝试使用像case when这样的
代码语言:javascript
运行
复制
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)
  1. 现在生成原始sql使用reflect
代码语言:javascript
运行
复制
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);]
}
  1. 现在可以批量更新,使用原始sql。
票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73702535

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档