我可以在更新后触发器中执行动态sql语句吗?

时间:2012-07-03 21:14:28

标签: oracle plsql triggers dynamic-sql

我使用以下声明:

query_str='SELECT :NEW.FIRST_NAME||:NEW.LAST_NAME INTO  HostID 
FROM INPUT_TABLE WHERE INPUT_ID='

触发器具有以下代码:

EXECUTE IMMEDIATE query_str ||:NEW.INPUT_ID;

更新INPUT_TABLE时出现以下错误:   ORA-01008:并非所有变量都绑定

如果我正在更新input_id = 111的记录,我认为Oracle只会执行以下语句:

SELECT :NEW.FIRST_NAME||:NEW.LAST_NAME INTO  HostID 
FROM INPUT_TABLE WHERE INPUT_ID=111

为什么会出现约束性问题?

我正在使用SQLDeveloper。

create or replace   
TRIGGER DATA_DETAIL_TRIG
AFTER INSERT OR UPDATE
ON INPUT_TABLE
FOR EACH ROW
 DECLARE
   DATA_SOURCE_ID_RET  NUMBER;
   resultcount        NUMBER;
   query_str          VARCHAR2(512);
   using_cl          VARCHAR2(512);
   HostId      VARCHAR2(256);
   DATA_SOURCE_ID       NUMBER;
   INPUT_ID         NUMBER(38,0);
   AUTOGENERATE_IND       VARCHAR2(1);
   autogen_const varchar(200);
   pragma autonomous_transaction;
   CURSOR C_DATA_SOURCES IS 
    SELECT DATA_SOURCE_ID
    FROM DATA_SOURCE_DETAIL
    WHERE AUTOGENERATE_IND='Y'
    AND DATA_SOURCE_REF.ACTIVE_IND='Y';
BEGIN


OPEN C_DATA_SOURCES;
LOOP
  FETCH C_DATA_SOURCES INTO DATA_SOURCE_ID_RET;
  EXIT WHEN C_DATA_SOURCES%NOTFOUND;
    query_str:=getHostQuery( DATA_SOURCE_ID_RET);
--SELECT :FIRST_NAME||:LAST_NAME||to_char(:DOB,'yyyy/mm/dd')    
From INPUT_TABLE WHERE     INPUT_ID=:INPUT_ID
using_cl:=getHostUsing(DATA_SOURCE_ID_RET);
--:NEW.FIRST_NAME, :NEW.LAST_NAME, :NEW.DOB, :NEW.INPUT_ID
EXECUTE IMMEDIATE query_str  INTO HostId USING using_cl;

  IF INSERTING THEN
    INSERT INTO DETAIL_TABLE
  (
  DETAIL_ID,
  INPUT_ID,
  HOST_ID,
  DATA_SOURCE_ID,
  NOTE,
  DATE_MODIFIED
  ) VALUES
  (
   DETAIL_SEQ.NEXTVAL,
    :NEW.INPUT_ID,
    HostId,
    DATA_SOURCE_ID_RET,
    'Autogenerate Data Source Insert for Insert Input',
    SYSDATE
  );

ELSIF UPDATING THEN



SELECT COUNT(DATA_SOURCE_ID) INTO resultcount FROM DETAIL_TABLE WHERE     
INPUT_ID=:NEW.INPUT_ID AND DATA_SOURCE_ID=DATA_SOURCE_ID_RET;
  IF resultcount>0 THEN


    UPDATE DETAIL_TABLE
    SET
  HOST_ID = HostId,
  NOTE ='Autogenerate Data Source Update for Update Input',
  DATE_MODIFIED =SYSDATE
  WHERE INPUT_ID=:NEW.INPUT_ID
  AND DATA_SOURCE_ID=DATA_SOURCE_ID_RET;


  ELSE
      INSERT INTO DETAIL_TABLE
  (
  DETAIL_ID,
  INPUT_ID,
  HOST_ID,
  DATA_SOURCE_ID,
  NOTE,
  DATE_MODIFIED
  ) VALUES
  (
  DETAIL_SEQ.NEXTVAL,
  :NEW.INPUT_ID,
  HostId,
   DATA_SOURCE_ID_RET,
   'Autogenerate Data Source Insert for Update Input ',

    SYSDATE
  );
END IF;
--end if insert or update inside update

END IF;
--end IF UPDATING
END LOOP;
Close C_DATA_SOURCES;

COMMIT;
END DATA_DETAIL_TRIG;
--end trigger

2 个答案:

答案 0 :(得分:3)

一旦将:new变量放在引号中,Oracle就会将其意义作为特殊触发变量丢失,并将它们解释为常规绑定变量。您可能需要在动态sql中使用USING子句。像

这样的东西
query_str:='SELECT :FIRST_NAME||:LAST_NAME
 FROM INPUT_TABLE WHERE INPUT_ID=:ID';
EXECUTE IMMEDIATE query_str INTO HostID USING 
  :NEW.FIRST_NAME,:NEW.LAST_NAME,:NEW.INPUT_ID;

更新

现在随着更多细节的出现,我想知道为什么你需要查询?从我所看到的,您只需从HostID中的某些值撰写INPUT_TABLE。但是,由于您已经将触发器附加到同一个表中,因此您已经拥有了所需的所有值,并且只需执行

HostID := :NEW.FIRST_NAME||:NEW.LAST_NAME;

只有在查询不同的表时,您的方法才有意义。在这种情况下,正如我所提到的,当您将:NEW放入:OLD时,您无法引用USING或{{1}}。不过,你可以从中组成其他价值。

答案 1 :(得分:0)

@Alex:下面是触发器。

create or replace   
TRIGGER DATA_DETAIL_TRIG
AFTER INSERT OR UPDATE
ON INPUT_TABLE
FOR EACH ROW
 DECLARE
   DATA_SOURCE_ID_RET  NUMBER;
   resultcount        NUMBER;
   query_str          VARCHAR2(512);
   using_cl          VARCHAR2(512);
   HostId      VARCHAR2(256);
   DATA_SOURCE_ID       NUMBER;
   INPUT_ID         NUMBER(38,0);
   AUTOGENERATE_IND       VARCHAR2(1);
   autogen_const varchar(200);
   pragma autonomous_transaction;
   CURSOR C_DATA_SOURCES IS 
    SELECT DATA_SOURCE_ID
    FROM DATA_SOURCE_DETAIL
    WHERE AUTOGENERATE_IND='Y'
    AND DATA_SOURCE_REF.ACTIVE_IND='Y';
BEGIN


OPEN C_DATA_SOURCES;
LOOP
  FETCH C_DATA_SOURCES INTO DATA_SOURCE_ID_RET;
  EXIT WHEN C_DATA_SOURCES%NOTFOUND;
    query_str:=getHostQuery( DATA_SOURCE_ID_RET);
--SELECT :FIRST_NAME||:LAST_NAME||to_char(:DOB,'yyyy/mm/dd')    
From INPUT_TABLE WHERE     INPUT_ID=:INPUT_ID
using_cl:=getHostUsing(DATA_SOURCE_ID_RET);
--:NEW.FIRST_NAME, :NEW.LAST_NAME, :NEW.DOB, :NEW.INPUT_ID
EXECUTE IMMEDIATE query_str  INTO HostId USING using_cl;

  IF INSERTING THEN
    INSERT INTO DETAIL_TABLE
  (
  DETAIL_ID,
  INPUT_ID,
  HOST_ID,
  DATA_SOURCE_ID,
  NOTE,
  DATE_MODIFIED
  ) VALUES
  (
   DETAIL_SEQ.NEXTVAL,
    :NEW.INPUT_ID,
    HostId,
    DATA_SOURCE_ID_RET,
    'Autogenerate Data Source Insert for Insert Input',
    SYSDATE
  );

ELSIF UPDATING THEN



SELECT COUNT(DATA_SOURCE_ID) INTO resultcount FROM DETAIL_TABLE WHERE     
INPUT_ID=:NEW.INPUT_ID AND DATA_SOURCE_ID=DATA_SOURCE_ID_RET;
  IF resultcount>0 THEN


    UPDATE DETAIL_TABLE
    SET
  HOST_ID = HostId,
  NOTE ='Autogenerate Data Source Update for Update Input',
  DATE_MODIFIED =SYSDATE
  WHERE INPUT_ID=:NEW.INPUT_ID
  AND DATA_SOURCE_ID=DATA_SOURCE_ID_RET;


  ELSE
      INSERT INTO DETAIL_TABLE
  (
  DETAIL_ID,
  INPUT_ID,
  HOST_ID,
  DATA_SOURCE_ID,
  NOTE,
  DATE_MODIFIED
  ) VALUES
  (
  DETAIL_SEQ.NEXTVAL,
  :NEW.INPUT_ID,
  HostId,
   DATA_SOURCE_ID_RET,
   'Autogenerate Data Source Insert for Update Input ',

    SYSDATE
  );
END IF;
--end if insert or update inside update

END IF;
--end IF UPDATING
END LOOP;
Close C_DATA_SOURCES;

COMMIT;
END DATA_DETAIL_TRIG;
--end trigger