【问题标题】:Oracle SQL stored procedure cursor is not looping or insertingOracle SQL 存储过程游标未循环或插入
【发布时间】:2018-08-21 14:06:02
【问题描述】:

我正在更新一个 oracle 存储过程以使用游标。目的是动态地将数据从一个表插入到另一个表。游标用于循环和自动递增字段 v_SRCROWID,由于某种原因它是 VARCHAR2。我没有制作这些表,所以我只是在有限使用 PL/SQL 的情况下尽我最大的努力。我知道序列通常是要走的路,但这不是一个选择。在游标中,我选择 max(SRCROWID) 并向其添加 1 以尝试增加 SRCROWID 字段,然后执行插入到表中的动态 sql 语句。问题是,它似乎没有在表中循环或插入任何内容。

create or replace PROCEDURE                                                     

LOOKUP_TABLE_INSERT 
(
P_SOURCE_DB IN VARCHAR2
, P_SOURCE_TABLE IN VARCHAR2
, P_TARGET_DB IN VARCHAR2
, P_TARGET_TABLE IN VARCHAR2
, P_COLUMN_NAME IN VARCHAR2
) AS 
l_sql_statement VARCHAR2(4000);
v_SRCROWID NUMBER(10);

CURSOR c_missingvalues
IS
SELECT MISSING_VALUES AS "PKEY_SRC_OBJECT"
, 1 as "VERSION_SEQ"
, 0 as "TIMELINE_ACTION"
, 1 as "HUB_STATE_IND"
, MISSING_VALUES as "ROLE_TP"
FROM ECH_ETL_BATCH_ID.REF_INTERMEDIATE
WHERE COLUMN_NM =  P_COLUMN_NAME --''''||P_COLUMN_NAME||''''
AND LOOKUP_TBL_NM = P_TARGET_TABLE; --''''||P_TARGET_TABLE||'''';

r_missingvalues c_missingvalues%ROWTYPE;
BEGIN

v_SRCROWID := 0;
l_sql_statement := '';

OPEN c_missingvalues;
LOOP
SELECT MAX(CAST(SRC_ROWID AS INTEGER)) INTO v_SRCROWID FROM 
ECH_ETL_BATCH_ID.C_S_LU_PTY_ROLE_TP;

FETCH c_missingvalues INTO r_missingvalues;
EXIT WHEN c_missingvalues%NOTFOUND;


SELECT 'INSERT INTO '|| P_TARGET_DB ||'.'|| P_TARGET_TABLE||' 
(PKEY_SRC_OBJECT, VERSION_SEQ, TIMELINE_ACTION, LAST_UPDATE_DATE, SRC_ROWID, 
HUB_STATE_IND, ROLE_TP) '||
'VALUES( ' ||''''|| r_missingvalues.PKEY_SRC_OBJECT ||''''|| 
','|| ''''|| r_missingvalues.VERSION_SEQ ||''''||
','|| ''''|| r_missingvalues.TIMELINE_ACTION ||''''|| 
','|| SYSDATE  ||
',' || v_SRCROWID ||' + 1' ||
','|| ''''|| r_missingvalues.HUB_STATE_IND  ||''''|| 
','|| ''''|| r_missingvalues.ROLE_TP ||''''|| 
');' INTO l_sql_statement FROM DUAL;
dbms_output.put_line(l_sql_statement);

EXECUTE IMMEDIATE l_sql_statement;
EXECUTE IMMEDIATE 'COMMIT';


END LOOP;
CLOSE c_missingvalues;
COMMIT;
END;

【问题讨论】:

  • 使用序列有什么问题?
  • 为什么不使用 eazy 方法 INTO INTO table (...) SELECT (...) FROM table... 而不是我很确定 Oracle 支持这个
  • 在直接使用存储过程输入和动态 SQL 时也要小心,例如 SELECT 'INSERT INTO '|| P_TARGET_DB ||'.'|| P_TARGET_TABLE||' 参数 P_TARGET_DBP_TARGET_TABLE 可用于注入盲 SQL 注入向量。阅读此 oracle-base.com/articles/10g/dbms_assert_10gR2
  • 我的工作场所不允许我使用序列,所以我一直在尝试解决方法。
  • 如果您有未提交的事务,在多用户环境下,如果没有序列,您将创建不一致的数据。

标签: sql oracle loops insert cursor


【解决方案1】:

你的动态语句很差。最好像这样使用它:

l_sql_statement := 'INSERT INTO '|| P_TARGET_DB ||'.'|| P_TARGET_TABLE||' 
  (PKEY_SRC_OBJECT, VERSION_SEQ, TIMELINE_ACTION, LAST_UPDATE_DATE, SRC_ROWID, 
  HUB_STATE_IND, ROLE_TP) 
VALUES 
   (:PKEY_SRC_OBJECT, :VERSION_SEQ, :TIMELINE_ACTION, :LAST_UPDATE_DATE, :SRC_ROWID, 
    :HUB_STATE_IND, :ROLE_TP)';

--dbms_output.put_line(l_sql_statement);

EXECUTE IMMEDIATE l_sql_statement USING 
    r_missingvalues.PKEY_SRC_OBJECT,
    r_missingvalues.VERSION_SEQ,
    r_missingvalues.TIMELINE_ACTION,
    SYSDATE,
    v_SRCROWID + 1, -- or better SEQUENCE_NAME.NEXTVAL,
    r_missingvalues.HUB_STATE_IND,
    r_missingvalues.ROLE_TP;
COMMIT;

或者甚至更好(假设你不能出于任何原因使用序列):

CREATE OR REPLACE PROCEDURE LOOKUP_TABLE_INSERT (
    P_SOURCE_DB IN VARCHAR2
    , P_SOURCE_TABLE IN VARCHAR2
    , P_TARGET_DB IN VARCHAR2
    , P_TARGET_TABLE IN VARCHAR2
    , P_COLUMN_NAME IN VARCHAR2
    ) AS

    l_sql_statement VARCHAR2(4000);
    v_SRCROWID NUMBER(10);

BEGIN

    SELECT MAX(CAST(SRC_ROWID AS INTEGER)) 
    INTO v_SRCROWID 
    FROM    ECH_ETL_BATCH_ID.C_S_LU_PTY_ROLE_TP;

    l_sql_statement := 'INSERT INTO '|| P_TARGET_DB ||'.'|| P_TARGET_TABLE||' 
        (PKEY_SRC_OBJECT, VERSION_SEQ, TIMELINE_ACTION, LAST_UPDATE_DATE, SRC_ROWID, 
        HUB_STATE_IND, ROLE_TP) 
        SELECT MISSING_VALUES, 1, 0, :LAST_UPDATE_DATE, :SRC_ROWID + ROWNUM, 1, MISSING_VALUES ' -- why MISSING_VALUES twice?
        ||' FROM ECH_ETL_BATCH_ID.REF_INTERMEDIATE
        WHERE COLUMN_NM =  :P_COLUMN_NAME
        AND LOOKUP_TBL_NM = :P_TARGET_TABLE';

    EXECUTE IMMEDIATE l_sql_statement USING SYSDATE, v_SRCROWID, P_COLUMN_NAME, P_TARGET_TABLE;
    COMMIT;
END;

【讨论】:

  • 嗯,这实际上与我最初拥有它的方式相似,但它无法编译,所以我将其更改为它的样子。奇怪的。它与你所拥有的一起工作。我不得不说你是一个绝对的救生员。谢谢!
  • 为了稍微简化一点,您可以直接在语句中编码sysdate,而不是定义占位符并将sysdate 作为绑定值传入。
  • 没错,我就是这么做的。再次感谢你。有没有不使用 ROWNUM 的情况下增加?有人告诉我这可能会在以后导致意外结果。
  • 是的,当然还有更好的方法——使用 SEQUENCE!
  • 相信我,如果由我决定,我会使用序列。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2012-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多