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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我有一个删除插入CTE以一种奇怪的方式失败相关的知识,希望对你有一定的参考价值。

这是它成功的一个例子:

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中的第二列是explicity 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

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

如果两个值都为null,为什么第二个例子会破坏我的错误?我已经仔细考虑了,这是唯一的功能差异。

答案

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

在第二个示例中,您提前一步提供NULL(在CTE中),必须键入表达式并为其指定类型unknown。对于其他constants(如数字常量:123),Postgres可以派生出更合适的默认数据类型,但NULL(或字符串文字'foo')可以是任何东西。并且在unknownjson之间没有定义类型转换。

将NULL转换为CTE中的正确数据类型以避免出现问题(正如您现在所发现的那样)。 或者使用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;
另一答案

诀窍似乎是将null转换为列类型应该是什么(在我的情况下为json):

with x as (
    delete from common.companies where id = '160d7ef2-807c-4fe0-bfed-7d282c031610' 
    returning row_to_json(companies) as old_data, null::json 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;

这需要在返回子句中完成,因为它创建了一个临时/伪表(没有强制转换)定义谁知道如何... Postgres不能从值推断出类型。因此,当您尝试将该值插入其他类型时,会出现转换错误。

以上是关于我有一个删除插入CTE以一种奇怪的方式失败的主要内容,如果未能解决你的问题,请参考以下文章

SqlConnection 状态以一种奇怪的方式变化

以一种奇怪的方式触地射击

Android:裁剪位图(以一种奇怪的方式)

为啥在 Racket 中以一种奇怪的方式定义 foldl?

为啥我的文本字符串以一种奇怪的方式换行? (HTML/CSS)

在 Xamarin IOS 的 UITableview 中更改滑动以删除按钮高度