小编典典

我有一个删除插入CTE,它以一种奇怪的方式失败了

sql

这是成功的一个例子:

with x as ( 
    delete from common.companies where id = '0f8ed160-370a-47bb-b4bf-2dcf79100a52' 
    returning row_to_json(companies) as old_data, null as new_data, 'common.companies' as model, id, 'delete' as action)
insert into edit_history (old_data, new_data, model, model_pk, action, submitter)
select old_data, null, model, id, action, '0b392013-f680-45a6-b19a-34f3d42d0120' from x;

INSERT 0 1

请注意,insert-select中的第二列是明确为null。

这是一个失败的示例:

with x as (
    delete from common.companies where id = '160d7ef2-807c-4fe0-bfed-7d282c031610' 
    returning row_to_json(companies) as old_data, null as new_data, 'common.companies' as model, id, 'delete' as action)
insert into edit_history (old_data, new_data, model, model_pk, action, submitter)                                                                   
select old_data, new_data, model, id, action, '0b392013-f680-45a6-b19a-34f3d42d0120' from x;

ERROR:  failed to find conversion function from unknown to json

请注意,在此示例中,我得到了new_data,而不是第二列中的显式null ,它从delete语句作为null返回。

如果两个值都为null,那么第二个示例为什么会因为这个错误而困扰我?我已经仔细检查了两者,这是唯一的功能差异。


阅读 134

收藏
2021-03-10

共1个答案

小编典典

在第一个示例中,您为语句提供了一个 尚未输入类型的 NULL INSERT

在第二个示例中,您较早一步(在CTE中)提供NULL,则必须键入表达式并为其指定type unknown。对于其他
常量

(例如数字常量123:),Postgres可以派生更合适的默认数据类型,但NULL(或字符串文字'foo')可以是 任何东西
。并且在unknown和之间没有定义类型转换json

在CTE中将NULL强制转换为正确的数据类型可以避免该问题(如您现在所知)。
或者text为时已晚,在铸造链中用作垫脚石。一切都可以投射到/投射出来text

您可以将演示简化为以下内容:

作品:

SELECT NULL::json;

失败:

SELECT new_data::json
FROM  (SELECT NULL AS new_data) t;

再次工作:

SELECT new_data
FROM  (SELECT NULL::json AS new_data) t;

或者:

SELECT new_data::text::json
FROM  (SELECT NULL AS new_data) t;
2021-03-10