如何使用动态列名和动态数据类型在oracle中创建动态表,而不包含任何视图或任何其他表类型

时间:2014-07-23 06:42:05

标签: oracle dynamic plsql

感谢大家,我们可以在execute immediate查询的帮助下动态创建表格。但是当我们创建一个表时,它已被创建,但如果我想用动态no列动态创建表,那么问题就出现了。实际上我创建了一个表,但是当我在表中创建了没有列的时候,引发了很多错误。以下是我在过程中在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

2 个答案:

答案 0 :(得分:2)

您不能在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

但还有另外一个问题。

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

SQL * Plus将仅提示替换变量一次:在脚本编译之前,在运行之前。然后在脚本中逐字替换变量,之后它将被编译并执行。

例如,当您运行脚本时,SQL * Plus会识别出有两个未知的文字(&colname&coldata),并会提示您。如果您提供值&#39; age&#39;和&#39; number&#39;对于他们来说,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

假设您提供了&#39; age&#39; for colname SQL * Plus会很乐意将其转换为:

colname varchar2(30) := 'age';

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

答案 1 :(得分:0)

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

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;