Golang中如何使用批量更新查询

Golang中如何使用批量更新查询 我有数千条记录需要在 MySQL 中更新,有没有办法一次性更新所有记录?

9 回复

Ashutosh_Prakash: 有没有办法一次性更新所有记录

通常来说,是的。你想更新什么?

更多关于Golang中如何使用批量更新查询的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我需要更新两列:列A和列B,条件是列C等于123(举例来说),并且在结构中,有时我会得到10条记录,有时会得到100条。

// 代码部分保持原样

只要遵循一些固定的规则,记录的数量并不重要。SQL并不关心你有多少条记录。你可以使用两层或更多层的CASE语句。

http://sqlfiddle.com/#!17/8c48e/3

你有更具体的例子吗?

是的,它在 MySQL 中可以工作,但我正在解组到结构体中的 JSON 数据不是固定的,它是动态的。有时我有 100 条记录,有时我有 50 条记录。那么,在 Go 语言中,我该如何编写动态的 case 语句呢?

感谢您的回复,Sibert。我想根据(WHERE条件)列C等于某个值来更新表中的两列(A和B)。这些值来自一个JSON数据列表,数据量很大,大约有上千条记录(包含列A、B、C的值)。因此,我需要使用MySQL和Golang一次性将这些值更新到表中。

我尝试提取那三个需要在MySQL中更新的键,并将JSON解组到结构体中。列A、B、C位于map[string]interface{}中,然后在map的for循环中执行更新查询(因此,对于我获取的每个数据,比如列A、B、C),我都在MySQL表中进行更新。 如果我使用case when语句,那么我将如何遍历case语句?

Ashutosh_Prakash:

我想根据条件更新表中两列(A, B)的数据。

我认为在 MySQL 中可以使用类似 CASE WHEN … THEN 的语句来实现。但我需要更多实际数据。

MySQL CASE Function

到目前为止你尝试了哪些方法?

如果我使用 case when 语句,那么我该如何遍历 case 语句呢?

SQL Fiddle SQL Fiddle | A tool for easy online testing and sharing of database problems…

这是一个用于测试和共享 SQL 查询的应用程序。

这是 Postgresql 的示例,但据我所知,它也应该适用于 MySQL。你不需要“遍历”。MySQL 会为你处理。

在Golang中可以使用MySQL的批量UPDATE语句配合IN子句或CASE语句来实现批量更新。以下是两种常见方法:

方法1:使用IN子句(适合不同ID更新不同值)

package main

import (
    "database/sql"
    "fmt"
    _ "github.com/go-sql-driver/mysql"
    "strings"
)

type UpdateData struct {
    ID    int
    Value string
}

func batchUpdateWithIN(db *sql.DB, data []UpdateData) error {
    if len(data) == 0 {
        return nil
    }

    // 构建ID列表和值映射
    ids := make([]string, 0, len(data))
    valueMap := make(map[int]string)
    
    for _, item := range data {
        ids = append(ids, fmt.Sprintf("%d", item.ID))
        valueMap[item.ID] = item.Value
    }

    // 构建CASE语句
    var caseBuilder strings.Builder
    caseBuilder.WriteString("CASE id ")
    
    for id, value := range valueMap {
        caseBuilder.WriteString(fmt.Sprintf("WHEN %d THEN '%s' ", id, value))
    }
    
    caseBuilder.WriteString("ELSE value END")

    // 执行批量更新
    query := fmt.Sprintf(
        "UPDATE your_table SET value = %s WHERE id IN (%s)",
        caseBuilder.String(),
        strings.Join(ids, ","),
    )

    _, err := db.Exec(query)
    return err
}

方法2:使用VALUES()构造临时表(适合大量数据)

func batchUpdateWithValues(db *sql.DB, data []UpdateData) error {
    if len(data) == 0 {
        return nil
    }

    // 构建VALUES部分
    var valuesBuilder strings.Builder
    for i, item := range data {
        if i > 0 {
            valuesBuilder.WriteString(", ")
        }
        valuesBuilder.WriteString(fmt.Sprintf("(%d, '%s')", item.ID, item.Value))
    }

    query := fmt.Sprintf(`
        UPDATE your_table t
        JOIN (VALUES %s) AS tmp(id, value)
        ON t.id = tmp.id
        SET t.value = tmp.value
    `, valuesBuilder.String())

    _, err := db.Exec(query)
    return err
}

方法3:使用预处理语句批量执行(最灵活)

func batchUpdateWithPreparedStmt(db *sql.DB, data []UpdateData) error {
    // 开启事务
    tx, err := db.Begin()
    if err != nil {
        return err
    }
    defer tx.Rollback()

    // 准备预处理语句
    stmt, err := tx.Prepare("UPDATE your_table SET value = ? WHERE id = ?")
    if err != nil {
        return err
    }
    defer stmt.Close()

    // 批量执行
    for _, item := range data {
        _, err := stmt.Exec(item.Value, item.ID)
        if err != nil {
            return err
        }
    }

    // 提交事务
    return tx.Commit()
}

方法4:使用ON DUPLICATE KEY UPDATE(适合有唯一键的表)

func batchUpsert(db *sql.DB, data []UpdateData) error {
    if len(data) == 0 {
        return nil
    }

    // 构建批量插入更新语句
    var valueStrings []string
    var valueArgs []interface{}
    
    for _, item := range data {
        valueStrings = append(valueStrings, "(?, ?)")
        valueArgs = append(valueArgs, item.ID, item.Value)
    }

    query := fmt.Sprintf(
        "INSERT INTO your_table (id, value) VALUES %s " +
        "ON DUPLICATE KEY UPDATE value = VALUES(value)",
        strings.Join(valueStrings, ","),
    )

    _, err := db.Exec(query, valueArgs...)
    return err
}

使用示例

func main() {
    db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
    if err != nil {
        panic(err)
    }
    defer db.Close()

    // 准备测试数据
    data := []UpdateData{
        {ID: 1, Value: "value1"},
        {ID: 2, Value: "value2"},
        {ID: 3, Value: "value3"},
        // ... 更多数据
    }

    // 使用方法1
    err = batchUpdateWithIN(db, data)
    if err != nil {
        fmt.Printf("批量更新失败: %v\n", err)
    }

    // 使用方法3(推荐用于数千条记录)
    err = batchUpdateWithPreparedStmt(db, data)
    if err != nil {
        fmt.Printf("预处理批量更新失败: %v\n", err)
    }
}

对于数千条记录,推荐使用方法3(预处理语句+事务),它提供了更好的错误处理和性能平衡。方法1和方法2在单条SQL语句中处理,但需要注意SQL语句长度限制。方法4适合需要插入或更新的场景。

回到顶部