I have a delete-insert CTE that fails in a strange manner

后端 未结 2 1762
粉色の甜心
粉色の甜心 2020-12-20 07:32

This is an example of it succeeding:

with x as ( 
    delete from common.companies where id = \'0f8ed160-370a-47bb-b4bf-2dcf79100a52\' 
    returning row_to_         


        
相关标签:
2条回答
  • 2020-12-20 08:07

    In the first example you provide a yet untyped NULL to the INSERT statement.

    In the second example you provide NULL one step earlier (in the CTE), the expression has to be typed and is assigned the type unknown. For other constants (like numeric constants: 123), Postgres can derive a more fitting default data type, but NULL (or a string literal 'foo') could be anything. And there is no type conversion defined between unknown and json.

    Cast NULL to the right data type in the CTE to avoid the problem (as you found yourself by now).
    Or use text as stepping stone in the casting chain if it's too late for that. Everything can be cast to / from text.

    You can simplify your demo to the following:

    Works:

    SELECT NULL::json;
    

    Fails:

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

    Works again:

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

    Or:

    SELECT new_data::text::json
    FROM  (SELECT NULL AS new_data) t;
    
    0 讨论(0)
  • 2020-12-20 08:08

    The trick seems to be to cast the null to whatever the column type should be (json in my case):

    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;
    

    This needs to be done in the returning clause because that's creating a temp/pseudo table that (without the cast) gets defined who knows how... Postgres can't infer the type from the value. So when you try to insert that value into a different type, you get the conversion error.

    0 讨论(0)
提交回复
热议问题