当前位置: 首页 > 知识库问答 >
问题:

试图用CASE语句更新多行时,Postgres挂起在大表上

禄星腾
2023-03-14

我正在尝试使用postgres更新多行,我正在使用以下代码:

UPDATE foobar SET column_a = CASE
  WHEN column_b = '123' THEN 1
  WHEN column_b = '345' THEN 2
END;

如果我创建一个新表,它可以完美地工作,但是当在具有800万行的大表上运行它时,它会无限期地挂起。我首先在管理员(Web界面)和控制台中尝试。

然而,这工作得很好:

UPDATE foobar SET column_a=1 WHERE column_b='123';

我不太愿意在我的代码中实现这种方法,因为我一次会有数千个更新,并且更愿意将它们放在一个语句中。关于为什么第一个例子会挂postgres,而第二个例子会很好地工作,有什么想法吗?我只是仔细检查了一下,我没有在桌子上应用任何规则。

共有2个答案

鲁望
2023-03-14

我保留这个问题,以防有人遇到这个问题。

这个查询是罪魁祸首:

UPDATE foobar SET column_a = CASE
  WHEN column_b = '123' THEN 1
  WHEN column_b = '345' THEN 2
END;

问题是它缺少 WHERE 语句,因此它尝试更新所有行。对于大型数据库,这可能是一个问题,在我的情况下,它只是超时了。一旦我在那里添加了where语句,它就解决了这个问题。

解决办法是:

UPDATE foobar SET column_a = CASE
   WHEN column_b = '123' THEN 1
   WHEN column_b = '345' THEN 2
END
WHERE column_b IN ('123','345')
赵朝
2023-03-14

声明:

CASE
  WHEN column_b = '123' THEN 1
  WHEN column_b = '345' THEN 2
END;

…只是简称:

CASE
  WHEN column_b = '123' THEN 1
  WHEN column_b = '345' THEN 2
  ELSE NULL
END

这意味着,如果没有 WHERE 子句,您的 UPDATE 语句不仅仅是“尝试”,它实际上会更新表中的每一行,其中大部分都为 NULL
也许,列上的非空约束可以防止数据丢失...

我将同时获得数千个更新,并且更愿意将它们放在一个语句中。

对于大型集合,速度更快(更短):

UPDATE foobar f
SET    column_a = val.a
FROM  (
   VALUES
     (123, 1)
    ,(345, 2)
   ) val(b, a)
WHERE f.column_b = val.b

加入一个集合,就可以轻松地遍历每一行的CASE分支的长列表。随着名单的增加,这种差异将迅速扩大。

此外,请确保在column_b上有索引。

您可以将VALUES表达式替换为任何产生适当行的表、视图或子选择。

注意:< br >我假设< code>column_a和< code>column_b的类型为< code>integer。在这种情况下,您问题中的< code>'123'前后的单引号没有任何帮助。你最好使用一个数字文字而不是字符串文字。(尽管它也适用于字符串文字。)

'123'之类的字符串文字默认为未知类型。
123之类的数字文字默认为integer-或bigint/数字如果数字太大。

如果您正在处理非默认数据类型,则必须显式转换。看起来像:

...
FROM  (
   VALUES
     ('123'::sometype, '1'::sometype)  -- first row defines row type
    ,('345', '2')
   ) val(b, a)
...
 类似资料:
  • 问题内容: 我想使用case语句更新表,查询是这样的… 您能告诉我正确的逻辑以使用case语句完成查询吗 问题答案: 您必须四处交换语法。case语句将应用于您要更新的每个值… 看来您实际上想要的是if语句。 希望能有所帮助

  • 问题内容: 我有这些表和值: 我想使用表1中的值及其各自的ID更新表2中的所有值。 有没有办法通过简单的SQL查询来做到这一点? 问题答案: 运行选择以确保它是您想要的 更新 另外,请考虑使用,以便在需要时可以将其回滚,但请在满意时再进行确认。

  • 问题内容: 我的结构表如下: 我需要使用一条语句一次更新三行,以便第二列分别为5、3、2。 我使用以下查询,但似乎缺少一些内容 我的问题是这样吗?如果没有,我可以使用语句吗?或者我只能选择在一个语句中使用它来实现这一点? 请注意,这是为了 问题答案: 好吧,根据您给的小提琴,我尝试了这些,对我有用 我没有使用where条件

  • Erlang提供case语句,可用于根据case语句的输出执行表达式。 本声明的一般形式是 - 语法 (Syntax) case expression of value1 -> statement#1; value2 -> statement#2; valueN -> statement#N end. 本声明的一般工作如下 - 要评估的表达式放在case语句中。 这通常会评估为

  • 除非编译器强制要求,括号在 case 语句里面是不必要的。但是当一个 case 包含了多行语句的时候,需要加上括号。 switch (condition) { case 1: // ... break; case 2: { // ... // Multi-line example using braces

  • Mysql跨表、多表更新SQL语句总结 MySQL可以在一个SQL语句中更新多张表的记录,也可以通过多个表之间的关联关系更新某个表的数据。 假定目前有两张表goods和goods_price表,前者是保存商品的具体信息,后者是保存商品的价格,具体的表结构如下: create table goods ( `id` int unsigned primary key auto_increment, `g