以编程方式向Oracle表中添加列

以编程方式向Oracle表中添加列,oracle,plsql,add,Oracle,Plsql,Add,我正在尝试做一些非常简单的事情。。。让我举一个例子。 假设我有一个包含多个列的表,让我们将其中一列称为“u”。此列只有3个不同的值,即。0、1和2。 我想创建三个附加列u_0、u_1和u_2,如下所示: If u = 0, then u_0 = 1, u_1 = 0 and u_2 = 0 If u = 1, then u_0 = 0, u_1 = 1 and u_2 = 0 If u = 2, then u_0 = 0, u_1 = 0 and u_2 = 1 这只是一个例子。有几个像u这样

我正在尝试做一些非常简单的事情。。。让我举一个例子。 假设我有一个包含多个列的表,让我们将其中一列称为“u”。此列只有3个不同的值,即。0、1和2。 我想创建三个附加列u_0、u_1和u_2,如下所示:

If u = 0, then u_0 = 1, u_1 = 0 and u_2 = 0
If u = 1, then u_0 = 0, u_1 = 1 and u_2 = 0
If u = 2, then u_0 = 0, u_1 = 0 and u_2 = 1
这只是一个例子。有几个像u这样的列,有三个以上不同的值,我需要为所有这些变量做类似的列添加。 是否可以用Oracle PL/SQL编写一个程序,这可以有效地做到这一点? 感谢和问候,
Dibyendu

虚拟专栏怎么样?您必须手动添加它们,但这些值是通过编程方式计算(和更新)的:

ALTER TABLE mytable ADD (u_0 NUMBER GENERATED ALWAYS
    AS (CASE u WHEN 0 THEN 1 ELSE 0 END) CHECK (u_0 IN (0,1)));

虚拟专栏怎么样?您必须手动添加它们,但这些值是通过编程方式计算(和更新)的:

ALTER TABLE mytable ADD (u_0 NUMBER GENERATED ALWAYS
    AS (CASE u WHEN 0 THEN 1 ELSE 0 END) CHECK (u_0 IN (0,1)));

我认为以下存储过程满足您的需要:

create or replace procedure expandcolumn 
(
  colname in varchar2  
) as 
  v_max integer;
  v_col_index integer := 0;
  v_sql_ddl varchar2(2000) := 'alter table demo add (';
  v_sql_update varchar2(2000) := 'update demo set ';
  v_sep varchar2(3) := ', ';
begin
  -- Retrieve the maximum value of the column so we know how many columns to add
  execute immediate 'select max(' || colname || ') from demo' into v_max;

  -- Starting from zero, prepare the DDL and UPDATE statements for each new column
  for v_col_index in 0..v_max loop
    if v_col_index = v_max then
      v_sep := null; -- We don't need a comma separator after the last column
    end if;

    v_sql_ddl := v_sql_ddl || colname || '_' || v_col_index || ' number(1)' || v_sep;
    v_sql_update := v_sql_update || colname || '_' || v_col_index ||
      '=decode(' || colname || ',' || v_col_index || ', 1, 0)' || v_sep;
  end loop;

  v_sql_ddl := v_sql_ddl || ')';

  execute immediate v_sql_ddl; -- Add the new columns to the demo table
  execute immediate v_sql_update; -- Set the new column values (implicit commit)
end expandcolumn;
使用您希望扩展为多列的原始列名调用它,例如

create table demo (u number(1));
insert into demo values (0);
insert into demo values (2);
insert into demo values (1);
commit;
exec expandcolumn('U');
select * from demo;

         U        U_0        U_1        U_2
---------- ---------- ---------- ----------
         0          1          0          0
         2          0          0          1
         1          0          1          0

当然,您可能需要对更多内容(如表名和列宽)进行参数化,但为了简单起见,我省略了这些内容。

我认为以下存储过程满足您的需要:

create or replace procedure expandcolumn 
(
  colname in varchar2  
) as 
  v_max integer;
  v_col_index integer := 0;
  v_sql_ddl varchar2(2000) := 'alter table demo add (';
  v_sql_update varchar2(2000) := 'update demo set ';
  v_sep varchar2(3) := ', ';
begin
  -- Retrieve the maximum value of the column so we know how many columns to add
  execute immediate 'select max(' || colname || ') from demo' into v_max;

  -- Starting from zero, prepare the DDL and UPDATE statements for each new column
  for v_col_index in 0..v_max loop
    if v_col_index = v_max then
      v_sep := null; -- We don't need a comma separator after the last column
    end if;

    v_sql_ddl := v_sql_ddl || colname || '_' || v_col_index || ' number(1)' || v_sep;
    v_sql_update := v_sql_update || colname || '_' || v_col_index ||
      '=decode(' || colname || ',' || v_col_index || ', 1, 0)' || v_sep;
  end loop;

  v_sql_ddl := v_sql_ddl || ')';

  execute immediate v_sql_ddl; -- Add the new columns to the demo table
  execute immediate v_sql_update; -- Set the new column values (implicit commit)
end expandcolumn;
使用您希望扩展为多列的原始列名调用它,例如

create table demo (u number(1));
insert into demo values (0);
insert into demo values (2);
insert into demo values (1);
commit;
exec expandcolumn('U');
select * from demo;

         U        U_0        U_1        U_2
---------- ---------- ---------- ----------
         0          1          0          0
         2          0          0          1
         1          0          1          0

当然,您可能需要对更多内容(如表名和列宽)进行参数化,但为了简单起见,我省略了这些内容。

我认为没有简单的方法可以做到这一点,这是有充分理由的。Oracle有“executeimmediate”语句,但不允许DDL。DDL需要隐式提交。为什么不写一个sqlplus脚本呢?@LeorA-Execute immediate当然可以用于DDL。例如,
beginexecuteimmediate'createtablettest1(一个数字)';结束。Dibyendu-这些列需要多久更改一次?是否只需要创建一次列?U_0、U_1和U_2中的值是否需要与U的更改保持一致?假设这些值从未更改。。。我只需要创建一次附加列。最好的方面是,DibyEndu以编程方式将列添加到Oracle表中——这是一个非常糟糕的主意。我认为没有一种简单的方法可以做到这一点,而且有充分的理由。Oracle有“executeimmediate”语句,但不允许DDL。DDL需要隐式提交。为什么不写一个sqlplus脚本呢?@LeorA-Execute immediate当然可以用于DDL。例如,
beginexecuteimmediate'createtablettest1(一个数字)';结束。Dibyendu-这些列需要多久更改一次?是否只需要创建一次列?U_0、U_1和U_2中的值是否需要与U的更改保持一致?假设这些值从未更改。。。我只需要创建一次附加列。值得一提的是,DibyEndu以编程方式向Oracle表中添加列—这是一个非常糟糕的主意。