Oracleデータベース用の移行スクリプトをいくつか書いていますが、OracleにMySQLのIF EXISTS
構造に似たものがあることを望んでいました。
具体的には、MySQLでテーブルを削除したいときはいつでも、次のようにします。
DROP TABLE IF EXISTS `table_name`;
こうすれば、テーブルが存在しなくてもDROP
はエラーにならず、スクリプトは続行できます。
Oracleにも同様のメカニズムがありますか?テーブルが存在するかどうかを確認するために、次のクエリを使用できることに気づきました
SELECT * FROM dba_tables where table_name = 'table_name';
しかし、それをDROP
と結び付けるための構文は、私を免れています。
最善かつ最も効率的な方法は、「テーブルが見つかりません」という例外をキャッチすることです。これにより、テーブルが2回存在するかどうかをチェックするというオーバーヘッドを回避できます。 DROPが他の何らかの理由で失敗した場合(それが重要かもしれません)、それでも呼び出し側に例外が発生するという問題はありません。
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE ' || table_name;
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
END;
_ addendum _ 参考のために、他のオブジェクトタイプと同等のブロックを次に示します。
シーケンス
BEGIN
EXECUTE IMMEDIATE 'DROP SEQUENCE ' || sequence_name;
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -2289 THEN
RAISE;
END IF;
END;
見る
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;
お役に立てれば
jeffreyのコードを使用してテーブルを作成し、それが既に存在する場合はそれを削除する完全なコードを投稿したいだけでした(彼には賞賛、私ではありません!).
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
を指定すると、エラーが発生した場合にスクリプトは終了します。
また見なさい: WHENEVER SQLERROR Docs
1つの方法は 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;
/
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
もう1つの方法は、例外を定義してからその例外のみをキャッチし、他のすべてのものを伝播させることです。
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_metadata.get_ddlを使用して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タイプ、名前、および所有者は変数です。
あなたはいつでも自分でエラーを捉えることができます。
begin
execute immediate 'drop table mytable';
exception when others then null;
end;
他の言語のempty catch()のように、これを使いすぎるのは悪い習慣と考えられています。
よろしく
K
テーブルとスキーマの所有者を指定することを好みます。
大文字と小文字の区別にも注意してください。 (下記の "upper"節を見てください)。
TABLE以外の場所でも使えることを示すために、いくつかの異なるオブジェクトを投げました。
.............
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;
そしてTABLEの例:
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を作成します。これは単純にシングルコンパイルで動作します
私は以下の経済的解決法を好む
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;
残念ながら、存在する場合はドロップ、またはCREATE IF NOT EXISTなどはありません。
そこにロジックを含めるためにplsqlスクリプトを書くことができます。
http://download.Oracle.com/docs/cd/B12037_01/server.101/b10759/statements_9003.htm
私はOracle Syntaxにはあまり興味がありませんが、@ 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;
このようなブロックはあなたにとって役に立つかもしれません。
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;