Как я могу контролировать выполнение оператора SQL на основе структуры DB2? - PullRequest
0 голосов
/ 29 января 2020

Мы хотим запустить простой оператор SQL (удаление и создание индекса), но только если старый индекс еще не был удален. После поиска синтаксиса для IF в DB2 я пришел к следующему:

IF EXISTS (SELECT indname FROM SYSCAT.INDEXES WHERE INDNAME = 'TEST_CREATE_INDEX_OLD') 
THEN 
    DROP INDEX TEST_CREATE_INDEX_OLD;
    create index TEST_CREATE_INDEX_NEW on example_table
    (
        id,
        another_field
    );
END IF;

При запуске с SQuirrel (уже настроенным для работы с db2) или через командную строку, это Сценарий приводит к ошибке:

Неожиданный токен "IF EXISTS (SELECT indname FROM SYSCAT.INDEX" найден после "BEGIN-OF-STATEMENT". Ожидаемые токены могут включать в себя: "" .. SQLCODE = -104, SQLSTATE = 42601, DRIVER = 4.23.42 SQL Код: -104, SQL Состояние: 42601

Итак - что я делаю не так? Я что-то упустил или Есть ли другой способ достичь моей цели (проверить наличие $ thing в базе данных, выполнить соответствующий запрос), который до сих пор мне не приходил?

Ответы [ 2 ]

0 голосов
/ 29 января 2020

Вы должны использовать другой разделитель операторов, если вы хотите использовать составной оператор db2.
В Squirrel: Session -> Свойства сеанса -> SQL -> Разделитель операторов = @.
Индексы в Db2 полностью квалифицируется по 2 SYSCAT.INDEXES столбцам: INDSCHEMA и INDNAME. Поэтому желательно использовать оба этих поля в операторе SELECT для SYSCAT.INDEXEX, как в примере.
Нельзя использовать stati c DDL в составном операторе. Вместо этого используйте операторы EXECUTE IMMEDIATE.
Ниже приведен пример эмуляции UPDATE INDEX для индекса в схеме, равной CURRENT SCHEMA специальному реестру, установленному в сеансе.

BEGIN
IF EXISTS (SELECT indname FROM SYSCAT.INDEXES WHERE INDSCHEMA = CURRENT SCHEMA AND INDNAME = 'TEST_CREATE_INDEX_OLD') 
THEN 
    EXECUTE IMMEDIATE 'DROP INDEX TEST_CREATE_INDEX_OLD';
    EXECUTE IMMEDIATE'
    create index TEST_CREATE_INDEX_NEW on example_table
    (
        id,
        another_field
    )
    ';
END IF;
END
@
0 голосов
/ 29 января 2020

Если оператор IF действителен только в составном блоке SQL (т. Е. Внутри блока хранимой процедуры / процедуры / функции / анонимного блока).

Он недопустим автономно, как показывает ваш вопрос и именно поэтому Db2 выдает ошибку -104.

Вы можете посмотреть объяснение sqlcode -104, просмотрев SQL0104N в бесплатном онлайн-центре знаний Db2 по этой ссылке .

Чтобы иметь возможность использовать состав- SQL в вашем инструменте Squirrel- SQL, вам необходимо настроить белка для использования альтернативного терминатора оператора. Google это. В приведенных ниже примерах я показываю терминатор оператора @ (для разделения блока).

Вот два разных способа сделать то, что вы хотите с Db2-Linux / Unix / Windows, каждый из которых использует анонимный блок. Возможны и другие подходы.

В этом примере drop-index будет работать только в том случае, если имя-индекс существует в текущей схеме:

begin declare v_index_exists integer default 0; select 1 into v_index_exists from syscat.indexes where indname = 'TEST_CREATE_INDEX_OLD'; if v_index_exists = 1 then execute immediate('drop index TEST_CREATE_INDEX_OLD'); execute immediate('create index TEST_CREATE_INDEX_NEW on example_table ( id, another_field)'); end if; end@

В этом примере drop-index всегда будет работать, но блок не будет прерван, если индекс не существует (то есть он продолжит работу и не выдаст никакой ошибки).

begin declare v_no_such_index integer default 0; declare not_exists condition for sqlstate '42704'; declare continue handler for not_exists set v_no_such_index=1; execute immediate('drop index TEST_CREATE_INDEX_OLD'); execute immediate('create index TEST_CREATE_INDEX_NEW on example_table ( id, another_field)'); end@

...