Индекс не создается с помощью хранимой процедуры - Oracle - PullRequest
1 голос
/ 27 мая 2019

У меня есть эта хранимая процедура для создания индекса для таблицы:

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.

Я не могу понять, почему хранимая процедура не создает индексы. Можете ли вы помочь?

1 Ответ

4 голосов
/ 27 мая 2019

Динамический оператор, который вы пытаетесь выполнить с помощью 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.

...