【问题标题】:Can I execute a dynamic sql statement in an after update trigger?我可以在更新后触发器中执行动态 sql 语句吗?
【发布时间】:2012-07-04 09:06:27
【问题描述】:

我正在使用以下语句:

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

【问题讨论】:

    标签: oracle plsql triggers dynamic-sql


    【解决方案1】:

    一旦您将: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;
    

    更新。

    现在随着更多细节的出现,我想知道你为什么需要查询?据我所知,您只需从INPUT_TABLE 中的一些值组成HostID。但是由于您已经将触发器附加到同一个表,因此您已经拥有所需的所有值并且可以简单地做

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

    只有在查询不同的表时,您的方法才有意义。在这种情况下,正如我所提到的,当您将 :NEW:OLD 放在 USING 中时,您不能引用它们。不过,您可以从它们中组合其他值。

    【讨论】:

    • USING 只是绑定变量。但是您可以在查询之前构造特定的文本并传递它。喜欢str:=:new.ssn||.:new.dob 然后用USING str 调用它。
    • @JeanneLane - 您是使用qry_str 变量来保存语句,还是直接运行它?如果是后者,语句周围有单引号吗? EXECUTE IMMEDIATE 'SELECT ... ' INTO HostID USING ...
    • 您不能在using 子句中使用某些字符串。你需要有同样多的真实参数并且你有绑定变量。我明白你的问题是什么。我会想一个好办法来解决它。同时,请将您的 sql 复制到主要问题并删除您的答案。
    • 其实很简单。在 getHostQuery 中直接编写响应:select first_name||last_name from input_table where input_id=:id。使用using DATA_SOURCE_ID_RET 调用它。我假设 first_name、last_name 等是表中的固定列,对吧?
    • 我在答案中添加了更新。我认为您甚至不需要查询!但是,如果您真的想这样做 - 是的,只需使用列名,您将从表中获取值。不需要:新。
    【解决方案2】:

    @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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-02
      • 1970-01-01
      • 2017-10-06
      相关资源
      最近更新 更多