【问题标题】:Bulk Update multiple rows in same query using PostgreSQL使用 PostgreSQL 批量更新同一查询中的多行
【发布时间】:2020-11-03 09:36:31
【问题描述】:

我希望在一个语句中更新 PostgreSQL 和 Go 中的多行。有没有办法做如下的事情?

UPDATE table 
SET column_a = "FINISH", 
    column_b = 1234 
WHERE id = '1',
    column_a = "UNFINISH", 
    column_b = 3124 
WHERE id = '2' 

如果用 go 语言执行,是否有示例?

【问题讨论】:

    标签: sql postgresql go sql-update case


    【解决方案1】:

    我喜欢使用派生表来构建它:

    UPDATE t
        SET column_a = v.column_a,
            column_b = v.column_b
        FROM (VALUES (1, 'FINISH', 1234),
                     (2, 'UNFINISH', 3124)
             ) v(id, column_a, column_b)
        WHERE v.id = t.id;
    

    这使得添加附加值(ids 和列)变得简单,而不会使查询复杂化。它也不太容易出现意外错误。

    【讨论】:

      【解决方案2】:

      在 postgresql 中,您可以使用此处答案中描述的 update-from-values 方法:Update multiple rows in same query using PostgreSQL

      在 Go 中你可以这样实现:

      func updateWithSlice(slice []T) error {
          var queryString = `UPDATE "table" AS t SET (
              "column_a"
              , "column_b"
          ) = (
              x."column_a"::text
              , x."column_b"::integer
          )
          FROM (VALUES` // `
      
          numColumns := 3 // the number of columns you want to update + 1 for the id column
          params := make([]interface{}, len(slice)*numColumns)
          for i, t := range slice {
              pos := i * numColumns
      
              params[pos+0] = t.ColumnA
              params[pos+1] = t.ColumnB
              params[pos+2] = t.Id
      
              queryString += `($` + strconv.Itoa(pos+1) +
                  `,$` + strconv.Itoa(pos+2) +
                  `,$` + strconv.Itoa(pos+3) +
                  `),`
          }
      
          queryString = queryString[:len(queryString)-1] // drop last ","
          queryString += ` ) AS x (
              "column_a"
              , "column_b"
              , "id"
          )
          WHERE t."id" = x."id"::integer` // `
      
          _, err := db.Exec(queryString, params...)
          return err
      }
      

      【讨论】:

        【解决方案3】:

        我想你想要:

        update mytable
        set 
            column_a = case when id = 1 then 'FINISH' else 'UNFINISHED' end,
            column_b = case when id = 1 then 1234     else 3124 end
        where id in (1, 2)
        

        理由:

        • where 子句只过滤你想要updateids,这样效率更高(前提是你在id 上有一个索引),并且简化了条件逻辑

        • id 看起来像一个数字,所以应该这样处理(即不要用引号括住文字值)

        • 文字字符串必须用单引号括起来——双引号代表标识符(例如列名)

        【讨论】:

          【解决方案4】:

          您可以使用 CASE 表达式。

          UPDATE table 
          SET 
            column_a = CASE WHEN id = '1' THEN 'FINISH'
                            WHEN id = '2' THEN 'UNFINISH'
                            ELSE 'SOMETHING'
                       END,
            column_b = CASE WHEN id = '1' THEN 1234
                            WHEN id = '2' THEN 3124
                            ELSE 0
                       END;
          

          【讨论】:

          • 这也将每隔一行更新为 column_a = 'SOMETHING' 和 'coloumn_b = 0`。我不认为这是意图。
          【解决方案5】:

          在 Postgres 中最有效的方法是使用UNNEST。这使您可以每列传递一个参数(而不是行数 x 列数)。对于您的示例,这看起来像:

          UPDATE table
          SET
            column_a=bulk_query.updated_column_a,
            column_b=bulk_query.updated_column_b
          FROM
            (
              SELECT * FROM UNNEST(
                ?::TEXT[],
                ?::TEXT[],
                ?::INT[]
              ) AS t(id, updated_column_a, updated_column_b)
            ) AS bulk_query
          WHERE
            users.id=bulk_query.id
          

          然后可以传递三个参数:

          [
            ["1", "2"],
            ["FINISH", "UNFINISH"],
            [1234, 3124]
          ]
          

          这种方法的好处在于,无论您要更新多少行,都只需要这 3 个参数。

          我在这篇博文中写了更多关于这个主题的文章:https://www.atdatabases.org/blog/2022/01/21/optimizing-postgres-using-unnest#update-multiple-records-to-different-values-in-a-single-query

          【讨论】:

            猜你喜欢
            • 2013-09-18
            • 1970-01-01
            • 1970-01-01
            • 2021-02-13
            • 1970-01-01
            • 2013-12-07
            • 1970-01-01
            • 2016-08-12
            • 2022-12-17
            相关资源
            最近更新 更多