这是一个有趣的发现。通常,NULL没有假定的数据类型,如您在此处看到的:
SELECT pg_typeof(NULL);
pg_typeof
───────────
unknown
当VALUES
表格出现在图片中时,这会改变:
SELECT pg_typeof(core) FROM (
VALUES (NULL)
) new_values (core);
pg_typeof
───────────
text
此行为是在源代码中在描述https://doxygen.postgresql.org/parse__coerce_8c.html#l01373:
/*
* If all the inputs were UNKNOWN type --- ie, unknown-type literals ---
* then resolve as type TEXT. This situation comes up with constructs
* like SELECT (CASE WHEN foo THEN 'bar' ELSE 'baz' END); SELECT 'foo'
* UNION SELECT 'bar'; It might seem desirable to leave the construct's
* output type as UNKNOWN, but that really doesn't work, because we'd
* probably end up needing a runtime coercion from UNKNOWN to something
* else, and we usually won't have it. We need to coerce the unknown
* literals while they are still literals, so a decision has to be made
* now.
*/
(是的,由于出色的注释,PostgreSQL源代码相对容易理解,并且在大多数地方都可以使用。)
但是,可能的解决方法如下。假设您一直在生成VALUES
与给定表的所有列匹配的记录(其他情况请参见下面的第二个注释)。从您的示例中,一个小技巧可能会有所帮助:
SELECT (x).* FROM (VALUES ((TRUE, NULL, 1234)::fields)) t(x);
active │ core │ id
────────┼──────┼──────
t │ │ 1234
在这里,您可以使用转换为表格类型的行表达式,然后将其提取回表格中。
基于以上所述,您UPDATE
可能会像
UPDATE fields AS t set active = (x).active, core = (x).core
FROM ( VALUES
((true, NULL, 3419)::fields),
((false, NULL, 3420)::fields)
) AS new_values(x) WHERE (x).id = t.id;
笔记:
- 我删除了双引号,以提高人类可读性,但是可以保留它们,因为它们在生成(列)名称时会有所帮助。
- 如果仅需要列的子集,则可以为此创建自定义类型。以与上面相同的方式使用它们(在这里,我使用由表自动创建的类型,并保留后者的行结构)。
看一下dbfiddle上的全部工作。
Cannot cast type boolean to bigint in column 1
(错误点在第一个字段语句之间的::上)