如何从 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 immediatedbms_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”命令?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 PL/SQL 过程中访问 http URL?

如何从 Oracle 10G PL/SQL 函数和过程中查找所有表引用? [复制]

无法从 SQL*Plus 创建和执行 PL/SQL 过程

oracle SQL语句中怎么样调用存储过程

如何使用参数从 Oracle PL/SQL 执行 Java jar 文件?

PL_sql如何执行oracle存储过程