【问题标题】:Update all rows with one SQL query使用一个 SQL 查询更新所有行
【发布时间】:2016-05-15 16:10:14
【问题描述】:

我正在使用这个 PostgreSQL 表来存储配置变量:

CREATE TABLE SYS_PARAM(
 SETTING_KEY TEXT NOT NULL,
 VALUE_TYPE TEXT,
 VALUE TEXT
)
;

如何使用一条 SQL 语句更新所有配置设置值?

【问题讨论】:

  • 只需对每个参数使用单独的更新。
  • 是的,但努力是减少 SQL 查询的数量。如果我有数百行怎么办?我不能轻易维护这么多查询。
  • 除非您要解决特定的性能问题,否则尝试更新 EAV 数据模型中的多行是过早的优化。您可以将更新包装在事务中,以便它们同时发生。即使运行几百个查询需要几百毫秒,更改此类设置也应该很少见,那么这对整体性能的影响应该可以忽略不计。
  • 你能给我看一个交易的例子吗?
  • 恕我直言,当前表格缺少关键元素;它只允许存储一种配置。所以这不是 EAV 模型而是 AV 模型,这是相当无用的,除非用作实例化其他配置的模板。这也需要额外的关键元素。

标签: sql postgresql sql-update postgresql-9.1 postgresql-9.3


【解决方案1】:

您可以在最后使用where true,它会更新表中的所有行。 例如:

UPDATE table_name set table_column = value where true;

它将在一个 SQL 查询中更新所有行。

【讨论】:

    【解决方案2】:

    如果您计划随着时间的推移多次执行这些更新,最好有一个函数为您处理。您可以将表本身用作函数中可变参数的类型,如下所示:

    -- The function
    CREATE OR REPLACE FUNCTION update_sys_param(VARIADIC params sys_param[])
    RETURNS VOID
    AS $$
    BEGIN
    
      UPDATE sys_param
        SET value_type = upd.value_type, value = upd.value
      FROM
        sys_param src
      INNER JOIN
        UNNEST(params) upd
        ON  (src.setting_key = upd.setting_key);
    
    END; $$ LANGUAGE PLPGSQL;
    
    -- To call it
    SELECT update_sys_param(('SMTP_PORT','int','123'),('SMTP_OTHER','text','435343'));
    

    但是,如果这是一次性更新,您可以尝试以下两种方法之一:

    使用 JOIN 更新

    UPDATE sys_param
       SET
         value_type = new.value_type,
         value = new.value
    FROM
       sys_param src
    INNER JOIN
       new_params new --< this table/view/cte must already exist or you must create it.
       ON  (src.setting_key = new.setting_key);
    

    使用 CASE 更新

    UPDATE sys_param
    SET value = CASE setting_key
          WHEN 'SMTP_PORT' THEN '2100'
          (..and so on..)
          END;
    -- You would need to repeat the case statement if you intend on updating the value_type, too.
    

    【讨论】:

    • 对于UPDATE using CASE 的示例,我如何还可以更新列'value_type'? (以防万一)
    • @PeterPenzov 您需要添加类似的 case 语句。概念是一样的。我毫不犹豫地为你做所有的工作:-)。请自己试一试——你应该有足够的信息来这样做。这是最好的学习方式。
    • @PeterPenzov - 如果您在自行尝试后仍有问题,请随时告诉我,我很乐意为您提供指导。
    • @PeterPenzov - 这是因为您的 value 字段是 TEXT 并且您提供(某些)非 TEXT 数据类型(在这种情况下为 INT)。您应该确保使用正确的数据类型(文本/字符串)传递它们。
    • 是的,我找到了。谢谢!
    【解决方案3】:

    我想你可以通过相关更新来实现这一点。

    请参考以下帖子:

    https://www.ibm.com/support/knowledgecenter/ssw_i5_54/sqlp/rbafyexsub4.htm

    【讨论】:

    • 你能举个例子吗?
    • @PeterPenzov - 提供的链接 shankarsh15 包含 2 个示例。问题是,您需要另一个表,其中包含要更新源表的新值。这与直接更新源表一样多,甚至更多。
    【解决方案4】:

    您可以加入一个值列表并使用它进行更新:

    update sys_param
       set value = v.new_value
    from (
      values 
         ('SMTP_PORT', '123'), 
         ('SMTP_SERVER', 'new_server'),
         ('SMTP_USERNAME', 'Arthur')
    ) as v(skey, new_value)
    where v.skey = sys_param.setting_key;
    

    这假定setting_key 是该表的主键。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-16
      • 1970-01-01
      • 2019-09-08
      • 1970-01-01
      • 1970-01-01
      • 2022-06-22
      • 1970-01-01
      相关资源
      最近更新 更多