我正在尝试编写一些代码来在创建表之前检查表是否存在。首先,我试图运行以下内容:
BEGIN
create table IT.DEVOPS_UC_SERVER_REG_TABLE
(
agentname VARCHAR2(100) not null,
servername VARCHAR2(100) not null,
datelastdeployed TIMESTAMP(6) WITH TIME ZONE,
technology VARCHAR2(100) not null,
issetup VARCHAR2(10)
);
EXCEPTION
NULL;
END;/
但是,这似乎不是有效的PL / SQL代码。有谁知道为什么会这样?对于PL / SQL,DDL和DML之间有区别吗?
答案 0 :(得分:4)
是的,你可以使用动态SQL,即EXECUTE IMMEDIATE。
但是,请三思而后行 - 以这种方式创建表格并不常见。你为什么要这样做?
答案 1 :(得分:3)
oracle抛出的常见异常是“ORA-00955:名称已被现有对象使用”。但仅此一点不足以说明该表已经创建。由于在同一名称空间内,没有两个对象可以具有相同的名称:
https://docs.oracle.com/database/121/SQLRF/sql_elements008.htm#i78631
因此异常消息:“名称已被现有对象使用”
但是如果你知道这一点并想要一个匿名的pl / sql块:
declare
lc__ constant varchar2(100) := 'Anonymous PL/SQL Block';
already_created exception;
pragma exception_init(already_created, -955); -- ORA-00955: name is already used by an existing object
lv_stmt varchar2(32767);
begin
lv_stmt := q'[create table it.devops_uc_server_reg_table (
agentname varchar2(100) not null,
servername varchar2(100) not null,
datelastdeployed timestamp(6) with time zone,
technology varchar2(100) not null,
issetup varchar2(10))
]';
begin
execute immediate lv_stmt;
exception
when already_created then
dbms_output.put_line('Name already defined on an existing object');
when others then
raise;
end;
exception when others then
raise_application_error(-20777, lc__ || chr(10) || dbms_utility.format_error_stack);
end;
答案 2 :(得分:2)
您应该使用这样的块:
DECLARE
L_CNT PLS_INTEGER;
BEGIN
SELECT COUNT(0)
INTO L_CNT
FROM ALL_TABLES T
WHERE T.TABLE_NAME = 'DEVOPS_UC_SERVER_REG_TABLE'
AND T.OWNER = 'IT';
IF L_CNT > 0 THEN
RETURN;
END IF;
EXECUTE IMMEDIATE 'create table IT.DEVOPS_UC_SERVER_REG_TABLE' || chr(10) ||
'(' || chr(10) ||
' agentname VARCHAR2(100) not null,' || chr(10) ||
' servername VARCHAR2(100) not null,' || chr(10) ||
' datelastdeployed TIMESTAMP(6) WITH TIME ZONE,' || chr(10) ||
' technology VARCHAR2(100) not null,' || chr(10) ||
' issetup VARCHAR2(10)' || chr(10) ||
')';
END;
答案 3 :(得分:1)
感谢所有伟大的答案。我决定将它们结合起来,这就是我最终使用的:
DECLARE
L_CNT PLS_INTEGER;
lv_stmt varchar2(32767);
BEGIN
--Check if the table already exists
SELECT COUNT(0)
INTO L_CNT
FROM ALL_TABLES T
WHERE T.TABLE_NAME = 'DEVOPS_UC_SERVER_REG_TABLE'
AND T.OWNER = 'IT';
IF L_CNT > 0 THEN
dbms_output.put_line('The table already exists');
RETURN;
END IF;
--Check if the constraint already exists
SELECT COUNT(0)
INTO L_CNT
FROM ALL_CONSTRAINTS C
WHERE C.CONSTRAINT_NAME = 'DEVOPS_UC_Server_Reg_PKEY'
AND C.OWNER = 'IT';
IF L_CNT > 0 THEN
dbms_output.put_line('The primary key constraint already exists');
RETURN;
END IF;
dbms_output.put_line('Creating table...');
/*
this code is auto-generated from DBMS_METADATA. It was accessed using the following query:
SELECT
DBMS_METADATA.GET_DDL( 'TABLE','DEVOPS_UC_SERVER_REG_TABLE','IT')
FROM DUAL;
so long as the tables do not exist, and the PRIMARY KEY NAME does not already exist
then this will create the table with the primary key constraint.
otherwise, you will run into ORA-0095: name already used by existing object (if table exists)
or ORA-02264: name already used by an existing constraint
TODO: make the table name and primary key constraint name variables for ease of use/robustness
*/
lv_stmt:=q'[
CREATE TABLE "IT"."DEVOPS_UC_SERVER_REG_TABLE"
( "AGENTNAME" VARCHAR2(100 CHAR) NOT NULL ENABLE,
"SERVERNAME" VARCHAR2(100 CHAR) NOT NULL ENABLE,
"DATELASTDEPLOYED" TIMESTAMP (6) WITH TIME ZONE,
"TECHNOLOGY" VARCHAR2(100 CHAR) NOT NULL ENABLE,
"ISSETUP" VARCHAR2(10 CHAR),
CONSTRAINT "DEVOPS_UC_Server_Reg_PKEY" PRIMARY KEY ("AGENTNAME", "SERVERNAME", "TECHNOLOGY")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
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 "IT" 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 "IT" ]';
execute immediate lv_stmt;
dbms_output.put_line('Table created successfully');
END;
答案 4 :(得分:0)
对于那些拥有MSSQL背景的人,您可能遇到过一两种情况,希望Oracle对IF NOT EXISTS() CREATE TABLE()
语法具有同等的条件。我的发行版需要在CRUSHER模式中创建一个名为A_OBF_Key的表。另一个运行中的版本也希望创建相同的表(具有相同的结构)。我们不知道将首先部署哪个版本,坦率地说,这并不重要。我们不想在两个发行版之间引入依赖关系,但是客户不想看到第二个发行版中出现的“ TABLE ALREADY EXISTS”错误。
对于EXECUTE IMMEDIATE
那些精打细算的人,有一种方法可以使用Oracle元数据,一个SQLPlus变量和两个文件来为SQLPlus编写脚本:一个在表存在时执行,一个在表存在时执行该表不存在。
我已经有一个名为“ OBF_Key.sql”的文件,它创建了A_OBF_Key表:
/* OBF_Key.sql */
PROMPT Handle OBF_Key objects...
PROMPT ... table
CREATE TABLE CRUSHER.A_OBF_Key(
KEY_NAME VARCHAR2(200) NOT NULL,
KEY_VALUE VARCHAR2(500) NOT NULL,
DESCRIPTION VARCHAR2(500) ,
SITE_CD VARCHAR2(3) NOT NULL,
EFFECTIVE_DTE DATE NOT NULL,
EXPIRE_DTE DATE ,
DATA_ENTRY_USER_ID VARCHAR2(30) NOT NULL,
DATA_ENTRY_DTE DATE DEFAULT SYSDATE NOT NULL
);
我还已经有了一个名为“ run_me_first.sql”的协调文件,该文件名为OBF_Key.sql。我创建了一个附加文件“ OBF_Key_Exists.sql”,该文件将处理已经创建A_OBF_Key的情况:
/* OBF_Key_Exists.sql */
PROMPT ...something else already installed OBF_Key, so moving on...
然后我将run_me_first.sql编辑为
赞:
/* run_me_first.sql */
SET DEFINE ON;
SET scan on;
COLUMN script_to_run NEW_VALUE script_to_run_now
PROMPT Check OBF_Key objects...
/* will return 'OBF_Key_Exists.sql' if the table is already created, or 'OBF_Key.sql' if it is not yet created */
SELECT CASE WHEN COUNT(*) > 0 THEN 'OBF_Key_Exists.sql' ELSE 'OBF_Key.sql' END AS script_to_run
FROM All_Tables
WHERE UPPER(owner) = 'CRUSHER'
AND UPPER(table_name) = 'A_OBF_Key';
--run the file named after the variable populated with the above query
@@&script_to_run_now
--these things I want to do whether or not the table already existed
GRANT SELECT ON CRUSHER.A_OBF_Key TO SECURITY;
GRANT SELECT ON CRUSHER.OBF_Key TO SECURITY;
CREATE OR REPLACE SYNONYM SECURITY.OBF_Key FOR CRUSHER.OBF_Key;
--put session settings back the way we started
SET scan off;
SET DEFINE OFF;