【问题标题】:Index not getting created using stored procedure - Oracle未使用存储过程创建索引 - Oracle
【发布时间】:2019-05-27 17:16:22
【问题描述】:

我有这个存储过程来在表上创建索引:

CREATE OR REPLACE PROCEDURE create_index (
    in_tb        VARCHAR2,
    in_index     VARCHAR2,
    in_columns   VARCHAR2,
    lc_status    OUT          NUMBER
) AS
    lc_affected   NUMBER;
    lc_stmt       VARCHAR2(1500);
BEGIN
    lc_stmt := 'BEGIN EXECUTE IMMEDIATE ''CREATE INDEX '
               || in_index
               || ' ON '
               || in_tb
               || ' ('
               || in_columns
               || ')''; END;';

    dbms_output.put_line(lc_stmt);
    dbms_utility.exec_ddl_statement(lc_stmt);
    lc_affected := SQL%rowcount;
    dbms_output.put_line('AFFECTED -->' || lc_affected);
    IF ( lc_affected > 0 ) THEN
        lc_status := 1;
    ELSE
        lc_status := 1;
    END IF;

END create_index;
/

我使用以下方法执行存储过程:

SET SERVEROUTPUT ON;
DECLARE
    lc_status   NUMBER;
BEGIN
    create_index('TABLE_1_LOAD', 'ON_RUN_INDEX', 'MY_ID', lc_status);
END;

但是,索引没有在表 TABLE_1_LOAD 中创建。

输出是:

BEGIN EXECUTE IMMEDIATE 'CREATE INDEX ON_RUN_INDEX ON TABLE_1_LOAD (MY_ID)'; END;
AFFECTED -->

PL/SQL procedure successfully completed.

我无法理解为什么存储过程不创建索引。你能帮忙吗?

【问题讨论】:

    标签: oracle plsql dynamic-sql


    【解决方案1】:

    您尝试通过exec_ddl_statement 运行的动态语句不是 DDL。它包含 DDL,但嵌入在匿名 PL/SQL 块中,这不是一回事。看起来dbms_utility 过程只是出于这个原因默默地忽略它。

    如果您简化语句以删除不必要的块,那么它将起作用:

    ...
    BEGIN
        lc_stmt := 'CREATE INDEX '
                   || in_index
                   || ' ON '
                   || in_tb
                   || ' ('
                   || in_columns
                   || ')';
    
    ...
    

    演示:

    create table table_1_load (my_id number);
    
    Table TABLE_1_LOAD created.
    
    CREATE OR REPLACE PROCEDURE create_index (
        in_tb        VARCHAR2,
        in_index     VARCHAR2,
        in_columns   VARCHAR2,
        lc_status    OUT          NUMBER
    ) AS
        lc_affected   NUMBER;
        lc_stmt       VARCHAR2(1500);
    BEGIN
        lc_stmt := 'CREATE INDEX '
                   || in_index
                   || ' ON '
                   || in_tb
                   || ' ('
                   || in_columns
                   || ')';
    
        dbms_output.put_line(lc_stmt);
        dbms_utility.exec_ddl_statement(lc_stmt);
        lc_affected := SQL%rowcount;
        dbms_output.put_line('AFFECTED -->' || lc_affected);
        IF ( lc_affected > 0 ) THEN
            lc_status := 1;
        ELSE
            lc_status := 1;
        END IF;
    
    END create_index;
    /
    
    Procedure CREATE_INDEX compiled
    
    SET SERVEROUTPUT ON;
    DECLARE
        lc_status   NUMBER;
    BEGIN
        create_index('TABLE_1_LOAD', 'ON_RUN_INDEX', 'MY_ID', lc_status);
    END;
    /
    
    CREATE INDEX ON_RUN_INDEX ON TABLE_1_LOAD (MY_ID)
    AFFECTED -->
    
    
    PL/SQL procedure successfully completed.
    

    “受影响”的数字仍然为空,因为execute_ddl_statement 不会导致设置SQL%rowcount,所以你不能依赖它来告诉你任何事情。但是索引已经创建:

    select object_type, object_name from user_objects where created > trunc(sysdate);
    
    OBJECT_TYPE         OBJECT_NAME                   
    ------------------- ------------------------------
    TABLE               TABLE_1_LOAD                  
    PROCEDURE           CREATE_INDEX                  
    INDEX               ON_RUN_INDEX                  
    

    可以使用execute immediate 运行您的原始语句,这实际上会设置SQL%rowcount,但由于您还没有运行任何DML,它真的毫无意义。为了证明这一点,使用(仍然不必要的)匿名块你得到 1;没有块,使用与上面相同的简化语句,你得到 0。

    【讨论】:

      猜你喜欢
      • 2015-06-24
      • 1970-01-01
      • 2017-12-21
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      • 2012-03-22
      • 1970-01-01
      相关资源
      最近更新 更多