如何在没有任何视图或任何其他表类型的情况下在 oracle 中创建具有动态列名和动态数据类型的动态表

Posted

技术标签:

【中文标题】如何在没有任何视图或任何其他表类型的情况下在 oracle 中创建具有动态列名和动态数据类型的动态表【英文标题】:how to create dynamic table in oracle with dynamic column name and dynamic data type with out any views or any other table type 【发布时间】:2014-07-23 06:42:05 【问题描述】:

谢谢大家,我们可以借助execute immediate查询动态创建表。但是,当我们创建一个表时,它就被创建了,但是如果我想动态地创建具有动态列数的表,那么就会提出问题。实际上我已经创建了一个表,但是当我没有与表一起创建列时,就会引发很多错误。以下是我在Oracle中编写的程序代码。

declare
    no_of_cols number:=&no_of_cols;
    colname varchar2(20);
    coldata varchar2(20);
    i number;
begin
    execute immediate 'create table smap1(nam varchar2(10))';
    age:='age';
    datf:='number'
    if(no_of_cols>=2) then
        for i in 2..no_of_cols loop
            colname:=age;
            coldata:=datf;
            execute immediate 'alter table smapl add '||colname||' '||coldata;  
        end loop;
    end if;
end;

如果 no_of_cols 为 5,则此代码使用相同类型的四列执行。然后我修改了代码并运行 plsql 程序。程序如下

declare
no_of_cols number:=&no_of_cols;
colname varchar2(20);
age varchar2(20);
datf varchar2(20);
coldata varchar2(20);
i number;
begin
    execute immediate 'create table smap1(nam varchar2(10))';
    if(no_of_cols>=2) then
        for i in 2..no_of_cols loop
            age :=&age;
            datf:=&datf;
            colname:=age;
            coldata:=datf;
            execute immediate 'alter table smapl add '||colname||' '||coldata;  
        end loop;
    end if;
end;

以下是创建上述程序时产生的错误

  [Error] Execution (13: 19): ORA-06550: line 13, column 19:
  PLS-00103: Encountered the symbol ";" when expecting one of the following:

  ( - + case mod new not null <an identifier>
  <a double-quoted delimited-identifier> <a bind variable>
  continue avg count current exists max min prior sql stddev
  sum variance execute forall merge time timestamp interval
  date <a string literal with character set specification>
  <a number> <a single-quoted SQL string> pipe
  <an alternatively-quoted string literal with character set specification>
  <an alternatively

我对上面的plsql做了一些修改,那么plsql代码如下

declare
no_of_cols number:=&no_of_cols;
colname varchar2(20):='&colname';
coldata varchar2(20):='&coldata';
i number;
begin
 execute immediate 'create table smap1(nam varchar2(10))';
if(no_of_cols>=2) then

    for i in 2..no_of_cols loop
       execute immediate 'alter table smapl add '||colname||' '||coldata;  
    end loop;
end if;
end;

然后执行后我收到以下错误,它不会动态读取列名

[Error] Execution (1: 1): ORA-02263: need to specify the datatype for this column
 ORA-06512: at line 10

【问题讨论】:

您正在混合使用 plsql 变量和 sql*plus 变量 (&amp;)。另外,您不能创建一个空表并向其添加列 - 您需要将字符串连接成一个 create table (...) 字符串,然后才能立即执行。 “引发了很多错误。”引发的错误是什么? 我忘记提及这些错误,现在我已经编辑了问题 你用什么客户端来执行这个?是 SQL*Plus 吗? Toad 12c 和 oracle 11g 作为客户端 【参考方案1】:

您不能在 EXECUTE IMMEDIATE 中对单个语句使用分号

这是documentation的引述:

除了多行查询,动态字符串可以包含任何 SQL 语句(没有最后的分号)或任何 PL/SQL 块(有最后的分号) .

EXECUTE IMMEDIATE 中删除分号。

execute immediate 'create table smap1(nam varchar2(10));'; -- this is your code
execute immediate 'create table smap1(nam varchar2(10))';  -- correct code, no semicolon at end

但是还有另一个问题。

您需要了解替换变量 (&amp;variable) 的工作原理

SQL*Plus 只会提示输入替换变量一次:就在脚本编译之前,在运行之前。然后在脚本中逐字替换变量,然后编译并执行。

例如,当您运行脚本时,SQL*Plus 识别出有两个未知文字(&amp;colname&amp;coldata),并会提示您。如果您为它们提供值 'age' 和 'number',SQL*Plus 将像这样重写脚本:

declare
    -- omitted to add clarity
begin
    execute immediate 'create table smap1(nam varchar2(10));';
    if(no_of_cols>=2) then
        for i in 2..no_of_cols loop
            colname:=age;
            coldata:=number;
            execute immediate 'alter table smapl add '||colname||' '||coldata;  
        end loop;
    end if;
end;

因此,如果您想将字符串文字分配给变量,并且想从替换变量中获取该字符串,则需要这样做:

colname varchar2(30) := '&colname'; -- notice the single quotes

假设您为 colname 提供了“年龄”,SQL*Plus 会很乐意将其转换为:

colname varchar2(30) := 'age';

因此,将替换变量放在循环中不会使 SQL*Plus 反复提示您输入它的值

【讨论】:

感谢您的解决方案。我在执行即时语句中删除了;。但问题是如果 no_of_cols 为 5,那么我想要五个不同的列,但是通过使用上面的代码,我得到了所有重复的列 是的,答案是“将替换变量放在循环中不会使 SQL*Plus 反复提示您输入它的值。”所以你不能那样做。将研究一种方法并回复您。 谢谢你,我有另一个错误。执行时它没有使用列名并显示错误名称[错误]执行(1:1):ORA-02263:需要指定此列的数据类型 ORA-06512:第 10 行 实际上我在创建另一个表时遇到了问题,然后我得到了错误 [Error] Execution (1: 1): ORA-02263: need to specify the datatype for this column ORA-06512: 在第 10 行表或视图不退出【参考方案2】:

为了更好地理解和分析,您应该这样做:

sqlcmd varhchar(30000);
begin
    sqlcmd := 'create table smap1(nam varchar2(10))';
    DBMS_OUTPUT.PUT_LINE(sqlcmd);
    execute immediate sqlcmd;
    if(no_of_cols>=2) then
        for i in 2..no_of_cols loop
            age :=&age;
            datf:=&datf;
            colname:=age;
            coldata:=datf;
            sqlcmd := 'alter table smapl add '||colname||' '||coldata;  
            DBMS_OUTPUT.PUT_LINE(sqlcmd);
            execute immediate sqlcmd;
        end loop;
    end if;

【讨论】:

当我在 Toad 的 oracle 11g 客户端中执行时,我收到一个错误 ORA-06550:第 15 行,第 19 列:PLS-00103:遇到符号“;”当期望以下之一时: continue avg count current exists max min prior sql stddev sum variance execute forall merge time timestamp间隔日期 管道 生成的SQL语句是什么? 那个语句是'alter table add datatype'

以上是关于如何在没有任何视图或任何其他表类型的情况下在 oracle 中创建具有动态列名和动态数据类型的动态表的主要内容,如果未能解决你的问题,请参考以下文章

ARCore – 如何在没有任何特征点的情况下在墙壁等表面上放置/创建对象?

在没有任何情节提要参考的情况下在控制器之间传递数据

如何在没有控制器调用的情况下在项目内的任何地方调用模型方法?

如何在不改变其位置的情况下在界面生成器中将子视图置于前面

如何在没有任何附加模块的情况下在迷你 Web 服务器中返回 json?

如何在没有任何 vue 库的情况下在 vue 回调中获取 http 响应标头(axios)