如何从 PL/SQL 过程执行“describe table_name”命令?
Posted
技术标签:
【中文标题】如何从 PL/SQL 过程执行“describe table_name”命令?【英文标题】:How can I execute 'describe table_name' command from a PL/SQL procedure? 【发布时间】:2016-04-18 10:40:46 【问题描述】:我在 Oracle 中有以下过程:
create procedure clone_tables
(current_table_name varchar2, cloned_table_name varchar2);
我必须克隆一个表,但我只收到它的名称。
在这种情况下,我想我必须得到它的结构,所以describe table_name
命令就足够了。
现在,execute immediate
或 dbms_sql.execute()
只使用 SQL 语句。
我还有其他方法可以做到吗?
【问题讨论】:
【参考方案1】:如果需要构建表的克隆,可以使用:
create or replace procedure clone_tables (current_table_name varchar2,
cloned_table_name varchar2
) as
begin
execute immediate
'create table ' || cloned_table_name ||
' as select * from ' || current_table_name
' where 1 = 0 ' ; /* to avoid copying records */
end;
/
这将建立一个与起始列完全相同的表,无需扫描所有列。这样你就不会复制起始表的记录;如果要复制记录,只需删除 WHERE
条件。
正如 Alex Poole 所说,这只会创建克隆表,但不会创建克隆表上存在的任何触发器、索引、外键等。
【讨论】:
【参考方案2】:查询 USER_TAB_COLUMNS 以获取列及其类型的列表。
【讨论】:
【参考方案3】:由于您提到 DESCRIBE (...),您必须使用 SQL*Plus - 或理解 SQL*Plus 命令的图形程序,如 Toad 或 SQL Developer。不幸的是,您不能在 SQL 或 PL/SQL 中执行 DESCRIBE 命令,因为 DESCRIBE 是 SQL*Plus 命令,它不是 SQL 或 PL/SQL 命令。
如果您使用 SQL Developer 或 Toad,它们有一个功能,您可以创建一个表,它会为您提供 SQL(不是 PL/SQL - 这不是必需的,只需要简单且非常快速的 SQL)重新创建表,包括约束和 cmets。下面我在练习 SQL 表上重现了在 SQL Developer 中使用此功能的输出。这只会创建表结构,而不是其数据;您仍然需要复制数据,例如使用
INSERT INTO (new_table) (SELECT * FROM old_table)
与 Alexsej 的解决方案相比,优势在于数据类型将被精确复制;在 Aleksej 的解决方案中,列不一定完全相同 - [例如,在旧表中,您可能有一个 VARCHAR2(300) 列;宽度 300 不会用他的方法复制,而是使用表中实际数据的宽度。] 编辑:正如 Alex Poole 在评论中指出的那样,我在这里(在方括号中)所说的是不正确的,使用 Aleksej 的解决方案克隆表将保留列宽等。(另外,他的方法不会复制约束,例如 NOT NULL 和 UNIQUE。) p>
我推荐的方法仍然不会重新创建触发器,但会重新创建约束和索引。
以下是 SQL Developer 可以为您做的事情的示例,您无需付出任何努力:
CREATE TABLE "INTRO"."COURSES"
( "CODE" VARCHAR2(6 BYTE) NOT NULL ENABLE,
"DESCRIPTION" VARCHAR2(30 BYTE) NOT NULL ENABLE,
"CATEGORY" CHAR(3 BYTE) NOT NULL ENABLE,
"DURATION" NUMBER(2,0) NOT NULL ENABLE,
CONSTRAINT "COURSES_PK" PRIMARY KEY ("CODE")
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 "SYSTEM" ENABLE,
CONSTRAINT "COURSES_CAT_CHK" CHECK (CATEGORY in ('GEN','BLD','DSG')) 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 "SYSTEM" ;
COMMENT ON COLUMN "INTRO"."COURSES"."CODE" IS 'Unique course code';
COMMENT ON COLUMN "INTRO"."COURSES"."DESCRIPTION" IS 'Course description (title)';
COMMENT ON COLUMN "INTRO"."COURSES"."CATEGORY" IS 'Course category (GEN, BLD or DSG)';
COMMENT ON COLUMN "INTRO"."COURSES"."DURATION" IS 'Course duration (in days)';
祝你好运!
【讨论】:
顺便说一句,如果您使用的是普通的 SQL*Plus 而不是图形界面之一,则可以通过多做一些工作来完成同样的工作。请提供一种方法或另一种方法。 您对CTAS的第一条评论不正确;数据类型被精确复制。这似乎也是一个 PL/SQL 练习,因此使用客户端功能可能超出范围。 (虽然问题当然没有提到这一点)。 哦,好的,我的立场是正确的。我会在我的回答中提到这一点。关于这是一个 PL/SQL 练习,您当然可能是对的;我解释说“还有其他方法可以做到吗?”表示他/她正在寻找任何方法,不一定是 PL/SQL。事实上,如果论坛参与者能够学习如何使用此类工具(任何此类工具)以便他们可以为他们的测试表发布创建和插入语句,我会非常高兴,这将使每个人的生活变得更加轻松。因此,如果我(和其他人)在这里的回答会鼓励 OP 以外的人这样做……我会很高兴的!谢谢,mathguy-ro 是的,它很模糊。您还可以使用dbms_metadata.get_ddl
在 PL/SQL 中获取相同的信息并使用它来创建克隆;尽管您也可以通过该包克隆一个对象,而无需看到 DDL,它处理约束但不处理其他索引 - 但它们可以在顶部轻松完成。同意发布 DDL 和 MCVE 的用户会很好......
对 - 这就是我在第一个评论中的建议,如果 OP 使用普通 SQLPlus(因为我倾向于在 99% 的时间里这样做),那么他/她仍然可以使用DBMS_metadata 包(我几乎可以肯定这就是 SQL Developer 和 Toad 在后台使用的东西)。以上是关于如何从 PL/SQL 过程执行“describe table_name”命令?的主要内容,如果未能解决你的问题,请参考以下文章
如何从 Oracle 10G PL/SQL 函数和过程中查找所有表引用? [复制]