2016-06-22 1 views
0

J'écris une fonction upsert pour une table en utilisant un bloc with pour la mise à jour, puis en faisant l'insertion conditionnellement. Je veux ensuite retourner les pks de la fonction entière et si oui ou non une insertion ou une mise à jour a été faite. Je pensais que cela fonctionnerait, mais je reçois une erreur d'ambiguïté pour les déclarations de retour. Qu'est-ce que je rate?Postgres return upsert ambigu

CREATE OR REPLACE FUNCTION eai.upsert_manufacturer(
    p_user_tag_ident text 
    , p_manuf_trade_name text 
    , p_company_name text 
    , p_manuf_code bigint default null 
    , p_mf_db_site text default '0000045000000100' 
    , p_mf_db_id bigint default 1 
    , p_phys_addr text default null 
    , p_phys_city_name text default null 
    , p_phys_state_abbr text default null 
    , p_phys_postal_code text default null 
    , p_phys_country_abbr text default null 
    , p_rstat_type_code smallint default 1 
) 
RETURNS TABLE(manuf_code bigint, mf_db_site text, mf_db_id bigint, action text) 
LANGUAGE plpgsql 
AS $function$ 
declare 
begin 

    return query 
    with update_outcome as (
     update eai.manufacturer as m 
      set 
       user_tag_ident = p_user_tag_ident::text 
       , manuf_trade_name = p_manuf_trade_name::text 
       , company_name = p_company_name::text 
       , phys_addr = p_phys_addr::text 
       , phys_city_name = p_phys_city_name::text 
       , phys_state_abbr = p_phys_state_abbr::text 
       , phys_postal_code = p_phys_postal_code::text 
       , phys_country_abbr = p_phys_country_abbr::text 
       , rstat_type_code = p_rstat_type_code::smallint 
       , gmt_last_updated = now() 
     where (m.manuf_code = p_manuf_code::bigint 
      and m.mf_db_site = p_mf_db_site::text 
      and m.mf_db_id = p_mf_db_id::bigint) 
      /* Since this table is unique on user_tag_ident */ 
      or m.user_tag_ident = p_user_tag_ident 
     returning manuf_code, mf_db_site, mf_db_id, 'update'::text as action 
    ) 
    , insert_outcome as (
     insert into eai.manufacturer(
      user_tag_ident 
      , manuf_trade_name 
      , company_name 
      , manuf_code 
      , mf_db_site 
      , mf_db_id 
      , phys_addr 
      , phys_city_name 
      , phys_state_abbr 
      , phys_postal_code 
      , phys_country_abbr 
      , rstat_type_code 
      , gmt_last_updated 
     ) 
     select 
      p_user_tag_ident::text 
      , p_manuf_trade_name::text 
      , p_company_name::text 
      , coalesce(p_manuf_code::bigint, (select max(mf.manuf_code)+1 from eai.manufacturer mf where mf.mf_db_site = p_mf_db_site and mf.mf_db_id = p_mf_db_id))::bigint as manuf_code 
      , p_mf_db_site::text 
      , p_mf_db_id::int 
      , p_phys_addr::text 
      , p_phys_city_name::text 
      , p_phys_state_abbr::text 
      , p_phys_postal_code::text 
      , p_phys_country_abbr::text 
      , p_rstat_type_code::smallint 
      , now() as now 
     where not exists (select 1 from update_outcome u) 
     returning manuf_code, mf_db_site, mf_db_id, 'insert'::text as action 
    ) 
    select 
     x.manuf_code 
     , x.mf_db_site 
     , x.mf_db_id 
     , x.action 
    from (
     SELECT 
      manuf_code 
      , mf_db_site 
      , mf_db_id 
      , action 
     FROM update_outcome u 
     UNION ALL SELECT 
      manuf_code 
      , mf_db_site 
      , mf_db_id 
      , action 
     FROM insert_outcome i 
    ) x; 

end; 
$function$; 

Exécution:

select * from eai.upsert_manufacturer(
    p_user_tag_ident:='Sent' 
    , p_manuf_trade_name:='Sent' 
    , p_company_name:='Sent' 
    , p_phys_addr:= '672' 
    , p_phys_city_name:= 'Blargh' 
); 

Et l'erreur:

Kernel error: ERROR: column reference "manuf_code" is ambiguous 
LINE 19:   returning manuf_code, mf_db_site, mf_db_id, 'update'... 
         ^
DETAIL: It could refer to either a PL/pgSQL variable or a table column. 
+1

Vous avez besoin d'un 'TABLE DE VERROUILLAGE eai.manufacturer EN MODE EXCLUSIF', sauf si vous savez que vous avez un verrou depuis l'extérieur de la fonction. Sinon, cela est bogué face à l'exécution simultanée. –

Répondre

0

Vous devez manuf_code là aussi loin que je peux voir. Le premier vient de update_outcome et le second de la partie insert.

+0

Je ne peux pas alias un insert cependant, y at-il un moyen de contourner cela? Donc je suis coincé. – KevinShaffer

+0

mais vous pouvez créer un alias qui sélectionne la pièce – JiriS

+0

Il s'avère que le problème était mon instruction de retour ayant les mêmes noms que l'upsert. – KevinShaffer