【问题标题】:I have a delete-insert CTE that fails in a strange manner我有一个删除插入 CTE,它以一种奇怪的方式失败
【发布时间】:2015-07-03 16:47:04
【问题描述】:

这是一个成功的例子:

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

请注意,插入选择中的第二列显式为空。

这是一个失败的例子:

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。

如果两个值都为空,为什么第二个示例会因为这个错误让我大吃一惊?我已经仔细研究过了,这是唯一的功能差异。

【问题讨论】:

    标签: sql postgresql casting common-table-expression


    【解决方案1】:

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

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

    在 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;
    

    【讨论】:

      【解决方案2】:

      诀窍似乎是将 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 无法从值推断类型。因此,当您尝试将该值插入其他类型时,会出现转换错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-11-07
        • 1970-01-01
        • 2017-01-17
        • 2017-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-03
        相关资源
        最近更新 更多