2016-07-06 17 views
0

我在觸發器表列名稱上寫了一個帶有循環的觸發器函數,我從不同列的不同表中調用函數。 該函數將列名插入數組並循環,以便將值插入到另一個模式和表中。Postgres SQL - 帶動態列名的觸發器

功能和觸發器創建腳本:

DROP TRIGGER cc_experiences_insert_row ON epro.experiences; 
CREATE TRIGGER cc_experiences_insert_row BEFORE INSERT ON epro.experiences FOR EACH ROW EXECUTE PROCEDURE epro.cc_update_subject_device(); 


CREATE OR REPLACE FUNCTION epro.cc_update_subject_device() 
RETURNS trigger AS $BODY$ 

DECLARE cols text[]; 
DECLARE table_column text; 
DECLARE ordinal integer; 
DECLARE v_study_event_oid character varying; 
DECLARE v_item_oid character varying; 
DECLARE v_crf_version_oid character varying; 
DECLARE insertRow BOOLEAN; 
DECLARE v_study_subject_id integer; 
DECLARE v_item_id integer; 
DECLARE v_crf_version_id integer; 
DECLARE v_study_event_definition_id integer; 
DECLARE v_study_event_id integer; 
DECLARE v_event_crf_id integer; 
DECLARE v_item_data_id integer; 

BEGIN 
    IF (TG_OP='INSERT') THEN 
     select study_subject_id from public.study_subject where label=NEW.subject_label INTO v_study_event_oid; 
     select array(select column_name::text from information_schema.columns where table_name = TG_TABLE_NAME and column_name not in ('id','name','subject_label','created','modified')) INTO cols; 

     FOR I IN array_lower(cols, 1)..array_upper(cols, 1) LOOP 

      select item_oid from epro.edc_epro_data_mappings where name = TG_TABLE_NAME and col = cols[I] INTO v_item_oid; 
      select crf_version_oid from epro.edc_epro_data_mappings where name = TG_TABLE_NAME and col = cols[I] INTO v_crf_version_oid; 
      select study_event_definition_oid from epro.edc_epro_data_mappings where name = TG_TABLE_NAME and col = cols[I] INTO v_study_event_oid; 

      select item_id from public.item where oc_oid = v_item_oid INTO v_item_id; 
      select crf_version_id from public.crf_version where oc_oid = v_crf_version_oid INTO v_crf_version_id; 
      select study_event_definition_id from public.study_event_definition where oc_oid = v_study_event_oid INTO v_study_event_definition_id; 

      SELECT nextval('study_event_study_event_id_seq') INTO v_study_event_id; 

      INSERT INTO public.study_event 
      (study_event_id,study_event_definition_id,study_subject_id,date_start,date_end,date_created,date_updated,update_id,subject_event_status_id,start_time_flag,end_time_flag,prev_subject_event_status,owner_id,status_id) 
      VALUES(v_study_event_id,v_study_event_definition_id,v_study_subject_id,now(),now(),now(),now(),1,4,'f','f',1,1,1); 

      SELECT nextval('event_crf_event_crf_id_seq') INTO v_event_crf_id; 

      INSERT INTO public.event_crf 
      (event_crf_id,study_event_id,crf_version_id,completion_status_id,date_completed,owner_id,status_id,date_created,study_subject_id,date_updated) 
      VALUES(v_event_crf_id,v_study_event_id,v_crf_version_id,1,now(),1,1,now(),v_study_subject_id,now()); 

      --SELECT ordinal from public.item_data 

      SELECT nextval('item_data_item_data_id_seq') INTO v_item_data_id; 

      table_column = 'NEW.'||cols[I]; 
      EXECUTE 'INSERT INTO public.item_data(item_data_id ,item_id , event_crf_id ,status_id , value , date_created, owner_id) 
      VALUES($1, $2 , $3 , 1, $4 , now(), 1)' 
      USING v_item_data_id,v_item_id,v_event_crf_id,NEW.cols[I]; 

      /*INSERT INTO public.item_data 
      (item_data_id ,item_id , event_crf_id ,status_id , value , date_created, owner_id) 
      VALUES(v_item_data_id, v_item_id , v_event_crf_id , 1, table_column , now(), 1); */ 
     END LOOP; 
    END IF; 
RETURN NEW; 
END; 
$BODY$ 
    LANGUAGE plpgsql VOLATILE 
    COST 100; 
ALTER FUNCTION epro.cc_update_subject_device() 
    OWNER TO postgres; 

運行是成功的,但是,當我試圖插入數據我得到了以下錯誤:

ERROR:記錄「新」有沒有場 「的cols」 CONTEXT:SQL語句 「SELECT NEW.cols [I]」 PL/pgSQL函數epro.cc_update_subject_device()線50在EXECUTE

哪有我動態地在表格的列上運行?

感謝,

+0

你不能用'plpgsql'來做到這一點。但是,你可以用'pltcl','plperl',也許可以做到這一點。你也可以選擇使用json/jsonb而不是你想要做的任何事情。 –

回答

0

如果你要插入的列到表public.item_data那麼你應該只需在INSERT語句中使用cols[I]的名字,但沒有EXECUTE說法,因爲沒有什麼動態有關查詢:

INSERT INTO public.item_data(item_data_id, item_id, event_crf_id, status_id, value, date_created, owner_id) 
VALUES(v_item_data_id, v_item_id, v_event_crf_id, 1, 'NEW.' || cols[I], now(), 1); 

如果要插入的列的值,而不是列的名稱,那麼您必須首先通過動態查詢來獲得該值:

EXECUTE format('SELECT NEW.$I', cols[I]) INTO table_column; 
INSERT INTO public.item_data(item_data_id, item_id, event_crf_id, status_id, value, date_created, owner_id) 
VALUES(v_item_data_id, v_item_id, v_event_crf_id, 1, table_column, now(), 1); 
+0

感謝您的回答,我用NEW。*參數構建了另一個數組,並從中選擇數值。謝謝。 – MRah

+0

我試圖使用您的答案代碼,但我在字段表中得到以下內容:「NEW.discomfort_id」 - 字段的名稱而不是字段值(如5) – MRah

+0

查看更新的回答 – Patrick