【发布时间】:2021-09-24 19:34:25
【问题描述】:
我有一个这样的数据库表:
| idx[PK] | a[numeric] | b[numeric] |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
| 4 | 4 | 4 |
| ... | ... | ... |
在 pgadmin4 中,我尝试使用一些空值更新此表,但我注意到以下查询失败:
UPDATE test as t SET
a = e.a,b = e.b
FROM (VALUES (1,NULL,NULL),(2,NULL,NULL),(3,NULL,NULL))
AS e(idx, a, b)
WHERE t.idx = e.idx
UPDATE test as t SET
a = e.a,b = e.b
FROM (VALUES (1,NULL,1),(2,NULL,2),(3,NULL,NULL))
AS e(idx, a, b)
WHERE t.idx = e.idx
错误信息是这样的:
ERROR: column "a" is of type numeric but expression is of type text
LINE 2: a = e.a,b = e.b
^
HINT: You will need to rewrite or cast the expression.
SQL state: 42804
Character: 43
但是,这将是成功的:
UPDATE test as t SET
a = e.a,b = e.b
FROM (VALUES (1,NULL,1),(2,2,NULL),(3,NULL,NULL))
AS e(idx, a, b)
WHERE t.idx = e.idx
如果我正在更新的列之一的新值都是NULL,那么查询将失败。但是,只要至少有一个值是数字但不是NULL,查询就会成功。这是为什么呢?
我确实在这里简化了我的真实案例,因为我的实际表有数百万行和 10 多列。使用 Python 和 psycopg2,当我尝试在一个查询中更新 50,000 行时,即使列中的值不是 NULL,仍然可能出现之前的错误。我猜这是因为系统会扫描一定数量的行来确定类型是否正确,而不是扫描全部 50,000 行。
因此,如何在我的现实世界中避免这种失败?有没有更好的查询来代替UPDATE?
非常感谢!
更新
来自@Marth 和@Gordon Linoff 的每个cmets,当我使用psycopg2 时,我在我的代码中执行了以下操作:
from psycopg2.extras import execute_values
sql = """UPDATE test as t SET
a = (e.a::numeric),
b = (e.b::numeric)
FROM (VALUES %s)
AS e(idx, a, b)
WHERE t.idx = e.idx"""
execute_values(cursor, sql, data)
cursor 来自数据库连接。 data 是我的值的 (idx, a, b) 形式的元组列表。
【问题讨论】:
-
发生这种情况是对的,因为当只有
null值时,postgresql 无法推断列的类型,所以它与text一起使用(尽管还有一个 @987654336 @ 伪类型,但它必须用于其他用途)。您可以将强制转换添加到第一行(好吧,所有行也可以,但只需第一行就足够了),例如FROM (VALUES (1, NULL::numeric, 1), ...)来指示列的类型。 -
非常感谢您的回复。由于我使用的是 psycopg2,因此我无法在
VALUES部分中添加类型,但可以在SET部分中添加它。请查看我的更新。
标签: postgresql psycopg2 pgadmin-4