Oracle: Если Таблица Существует
Я пишу некоторые сценарии миграции для базы данных Oracle и надеялся, что Oracle имеет что-то похожее на MySQL IF EXISTS строительство.
в частности, всякий раз, когда я хочу удалить таблицу в MySQL, я делаю что-то вроде
DROP TABLE IF EXISTS `table_name`;
таким образом, если таблица не существует,DROP не выдает ошибку, и скрипт может продолжить работу.
есть ли у Oracle подобный механизм? Я понимаю, что могу использовать следующий запрос, чтобы проверить, существует ли таблица или нет
SELECT * FROM dba_tables where table_name = 'table_name';
но синтаксис для связывания этого вместе с DROP ускользает от меня.
15 ответов:
лучший и самый эффективный способ-поймать исключение "таблица не найдена": это позволяет избежать накладных расходов на проверку, существует ли таблица дважды; и не страдает от проблемы, что если падение не удается по какой-то другой причине (что может быть важно) исключение все еще вызывается вызывающему:
BEGIN EXECUTE IMMEDIATE 'DROP TABLE ' || table_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;дополнительное соглашение Для справки, вот эквивалентные блоки для другого объекта типы:
последовательность
BEGIN EXECUTE IMMEDIATE 'DROP SEQUENCE ' || sequence_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2289 THEN RAISE; END IF; END;View
BEGIN EXECUTE IMMEDIATE 'DROP VIEW ' || view_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END;триггер
BEGIN EXECUTE IMMEDIATE 'DROP TRIGGER ' || trigger_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -4080 THEN RAISE; END IF; END;индекс
BEGIN EXECUTE IMMEDIATE 'DROP INDEX ' || index_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -1418 THEN RAISE; END IF; END;колонки
BEGIN EXECUTE IMMEDIATE 'ALTER TABLE ' || table_name || ' DROP COLUMN ' || column_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -904 THEN RAISE; END IF; END;Ссылка На Базу Данных
BEGIN EXECUTE IMMEDIATE 'DROP DATABASE LINK ' || dblink_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2024 THEN RAISE; END IF; END;Материализованного Представления
BEGIN EXECUTE IMMEDIATE 'DROP MATERIALIZED VIEW ' || mview_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -12003 THEN RAISE; END IF; END;тип
BEGIN EXECUTE IMMEDIATE 'DROP TYPE ' || type_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -4043 THEN RAISE; END IF; END;ограничения
BEGIN EXECUTE IMMEDIATE 'ALTER TABLE ' || table_name || ' DROP CONSTRAINT ' || constraint_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -2443 THEN RAISE; END IF; END;Планировщик Заданий
BEGIN DBMS_SCHEDULER.drop_job(job_name); EXCEPTION WHEN OTHERS THEN IF SQLCODE != -27475 THEN RAISE; END IF; END;пользователь / Схема
BEGIN EXECUTE IMMEDIATE 'DROP USER ' || user_name; /* you may or may not want to add CASCADE */ EXCEPTION WHEN OTHERS THEN IF SQLCODE != -1918 THEN RAISE; END IF; END;пакета
BEGIN EXECUTE IMMEDIATE 'DROP PACKAGE ' || package_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -4043 THEN RAISE; END IF; END;процедура
BEGIN EXECUTE IMMEDIATE 'DROP PROCEDURE ' || procedure_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -4043 THEN RAISE; END IF; END;функции
BEGIN EXECUTE IMMEDIATE 'DROP FUNCTION ' || function_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -4043 THEN RAISE; END IF; END;пространство
BEGIN EXECUTE IMMEDIATE 'DROP TABLESPACE' || tablespace_name; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -959 THEN RAISE; END IF; END;
declare c int; begin select count(*) into c from user_tables where table_name = upper('table_name'); if c = 1 then execute immediate 'drop table table_name'; end if; end;это для проверки, существует ли таблица в текущей схеме. Для проверки того, существует ли данная таблица уже в другой схеме, вам нужно будет использовать
all_tablesвместоuser_tablesи добавить условиеall_tables.owner = upper('schema_name')
Я искал то же самое, но я закончил писать процедуру, чтобы помочь мне:
CREATE OR REPLACE PROCEDURE DelObject(ObjName varchar2,ObjType varchar2) IS v_counter number := 0; begin if ObjType = 'TABLE' then select count(*) into v_counter from user_tables where table_name = upper(ObjName); if v_counter > 0 then execute immediate 'drop table ' || ObjName || ' cascade constraints'; end if; end if; if ObjType = 'PROCEDURE' then select count(*) into v_counter from User_Objects where object_type = 'PROCEDURE' and OBJECT_NAME = upper(ObjName); if v_counter > 0 then execute immediate 'DROP PROCEDURE ' || ObjName; end if; end if; if ObjType = 'FUNCTION' then select count(*) into v_counter from User_Objects where object_type = 'FUNCTION' and OBJECT_NAME = upper(ObjName); if v_counter > 0 then execute immediate 'DROP FUNCTION ' || ObjName; end if; end if; if ObjType = 'TRIGGER' then select count(*) into v_counter from User_Triggers where TRIGGER_NAME = upper(ObjName); if v_counter > 0 then execute immediate 'DROP TRIGGER ' || ObjName; end if; end if; if ObjType = 'VIEW' then select count(*) into v_counter from User_Views where VIEW_NAME = upper(ObjName); if v_counter > 0 then execute immediate 'DROP VIEW ' || ObjName; end if; end if; if ObjType = 'SEQUENCE' then select count(*) into v_counter from user_sequences where sequence_name = upper(ObjName); if v_counter > 0 then execute immediate 'DROP SEQUENCE ' || ObjName; end if; end if; end;надеюсь, что это помогает
просто хотел опубликовать полный код, который создаст таблицу и отбросит ее, если она уже существует, используя код Джеффри (слава Ему, а не мне!).
BEGIN BEGIN EXECUTE IMMEDIATE 'DROP TABLE tablename'; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; END; EXECUTE IMMEDIATE 'CREATE TABLE tablename AS SELECT * FROM sourcetable WHERE 1=0'; END;
С SQL * PLUS вы также можете использовать команду WHENEVER SQLERROR:
WHENEVER SQLERROR CONTINUE NONE DROP TABLE TABLE_NAME; WHENEVER SQLERROR EXIT SQL.SQLCODE DROP TABLE TABLE_NAME;С
CONTINUE NONEсообщение об ошибке, но сценарий будет продолжен. СEXIT SQL.SQLCODEскрипт будет завершен в случае ошибки.Читайте также: всякий раз, когда Sqlerror Docs
в oracle нет "DROP TABLE IF EXISTS", вам нужно будет сделать инструкцию select.
попробуйте это (я не разбираюсь в синтаксисе oracle, поэтому, если мои переменные ify, пожалуйста, простите меня):
declare @count int select @count=count(*) from all_tables where table_name='Table_name'; if @count>0 BEGIN DROP TABLE tableName; END
другой метод-определить исключение, а затем только поймать это исключение, позволяя всем остальным распространяться.
Declare eTableDoesNotExist Exception; PRAGMA EXCEPTION_INIT(eTableDoesNotExist, -942); Begin EXECUTE IMMEDIATE ('DROP TABLE myschema.mytable'); Exception When eTableDoesNotExist Then DBMS_Output.Put_Line('Table already does not exist.'); End;
один из способов-это использовать DBMS_ASSERT.SQL_OBJECT_NAME :
эта функция проверяет, что строка входного параметра является квалифицированным идентификатором SQL существующего объекта SQL.
DECLARE V_OBJECT_NAME VARCHAR2(30); BEGIN BEGIN V_OBJECT_NAME := DBMS_ASSERT.SQL_OBJECT_NAME('tab1'); EXECUTE IMMEDIATE 'DROP TABLE tab1'; EXCEPTION WHEN OTHERS THEN NULL; END; END; /
к сожалению нет, нет такой вещи, как падение, если существует, или создать, если не существует
вы можете написать сценарий plsql, чтобы включить логику там.
http://download.oracle.com/docs/cd/B12037_01/server.101/b10759/statements_9003.htm
Я не очень разбираюсь в синтаксисе Oracle, но я думаю, что сценарий @Erich будет чем-то вроде этого.
declare cant integer begin select into cant count(*) from dba_tables where table_name='Table_name'; if count>0 then BEGIN DROP TABLE tableName; END IF; END;
вы всегда можете поймать ошибку самостоятельно.
begin execute immediate 'drop table mytable'; exception when others then null; end;считается плохой практикой злоупотреблять этим, подобно пустому catch () ' es на других языках.
в отношении
К
Я предпочитаю указывать таблицу и владельца схемы.
следите за чувствительностью к регистру, а также. (см. "верхний" пункт ниже).
Я бросил несколько различных объектов, чтобы показать, что это может быть использовано в местах, кроме таблиц.
.............
declare v_counter int; begin select count(*) into v_counter from dba_users where upper(username)=upper('UserSchema01'); if v_counter > 0 then execute immediate 'DROP USER UserSchema01 CASCADE'; end if; end; / CREATE USER UserSchema01 IDENTIFIED BY pa$$word DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA UNLIMITED ON users; grant create session to UserSchema01;и пример таблицы:
declare v_counter int; begin select count(*) into v_counter from all_tables where upper(TABLE_NAME)=upper('ORDERS') and upper(OWNER)=upper('UserSchema01'); if v_counter > 0 then execute immediate 'DROP TABLE UserSchema01.ORDERS'; end if; end; /
BEGIN EXECUTE IMMEDIATE 'DROP TABLE "IMS"."MAX" '; EXCEPTION WHEN OTHERS THEN IF SQLCODE != -942 THEN RAISE; END IF; EXECUTE IMMEDIATE ' CREATE TABLE "IMS"."MAX" ( "ID" NUMBER NOT NULL ENABLE, "NAME" VARCHAR2(20 BYTE), CONSTRAINT "MAX_PK" PRIMARY KEY ("ID") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "SYSAUX" ENABLE ) SEGMENT CREATION IMMEDIATE PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "SYSAUX" '; END;// выполняя этот код, проверяет, существует ли таблица, а затем создает таблицу max. это просто работает в одной компиляции
и если вы хотите сделать его повторно вводимым и минимизировать циклы drop/create, вы можете кэшировать DDL с помощью dbms_metadata.get_ddl и воссоздать все с помощью конструкции, как это:
declare v_ddl varchar2(4000); begin select dbms_metadata.get_ddl('TABLE','DEPT','SCOTT') into v_ddl from dual; [COMPARE CACHED DDL AND EXECUTE IF NO MATCH] exception when others then if sqlcode = -31603 then [GET AND EXECUTE CACHED DDL] else raise; end if; end;Это всего лишь пример,внутри должен быть цикл с типом DDL, именем и владельцем, являющимися переменными.
блок, как это может быть для вас полезной.
DECLARE table_exist INT; BEGIN SELECT Count(*) INTO table_exist FROM dba_tables WHERE owner = 'SCHEMA_NAME' AND table_name = 'EMPLOYEE_TABLE'; IF table_exist = 1 THEN EXECUTE IMMEDIATE 'drop table EMPLOYEE_TABLE'; END IF; END;
Я предпочитаю следующее экономическое решение
BEGIN FOR i IN (SELECT NULL FROM USER_OBJECTS WHERE OBJECT_TYPE = 'TABLE' AND OBJECT_NAME = 'TABLE_NAME') LOOP EXECUTE IMMEDIATE 'DROP TABLE TABLE_NAME'; END LOOP; END;
Comments