Oracle 创建一个列,然后使用PL/SQL程序向其中添加数据

Oracle 创建一个列,然后使用PL/SQL程序向其中添加数据,oracle,plsql,Oracle,Plsql,我试图创建一个PL/SQL程序,在其中向表中添加一个列(称为AGE_GROUP),然后向该列中插入数据,但它似乎不起作用 DECLARE cust_age string(10); cust_inc string(10); cust_status string(10); BEGIN EXECUTE IMMEDIATE 'ALTER TABLE DATACOPY ADD(AGE_GROUP VARCHAR2(10));'; FOR emp IN (SELECT

我试图创建一个PL/SQL程序,在其中向表中添加一个列(称为AGE_GROUP),然后向该列中插入数据,但它似乎不起作用

    DECLARE
    cust_age string(10);
    cust_inc string(10);
    cust_status string(10);
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE DATACOPY ADD(AGE_GROUP VARCHAR2(10));';
    FOR emp IN (SELECT *
                FROM datacopy) LOOP
        cust_age := get_group_age(emp.ID);
        cust_inc := get_income_level(emp.ID);
        cust_status := fix_status(emp.ID);
      UPDATE datacopy SET AGE_GROUP = cust_age WHERE ID = emp.ID;
      UPDATE datacopy SET INCOME_LEVEL = cust_inc WHERE ID = emp.ID;
      UPDATE datacopy SET MARITAL_STATUS = cust_status WHERE ID = emp.ID;
      COMMIT;
    END LOOP;
END; 
我看到的错误是错误报告- ORA-06550:第12行第27列:
PL/SQL:ORA-00904:“年龄组”:不可接受的标识符这是因为首先解析块,只有在没有错误时才执行块。您会得到解析错误,因为在解析时datacopy表中没有年龄组列。您应该尝试使用动态SQL,ref cursor

并删除其中一个冒号,它应为以下内容:

EXECUTE IMMEDIATE 'ALTER TABLE DATACOPY ADD(AGE_GROUP VARCHAR2(10))';

这是因为首先解析块,然后在没有错误的情况下执行。您会得到解析错误,因为在解析时datacopy表中没有年龄组列。您应该尝试使用动态SQL,ref cursor

并删除其中一个冒号,它应为以下内容:

EXECUTE IMMEDIATE 'ALTER TABLE DATACOPY ADD(AGE_GROUP VARCHAR2(10))';

正如@Maxim所说,在解析PL/SQL块时,表中没有
AGE\u GROUP
列,因此

UPDATE datacopy SET AGE_GROUP = cust_age WHERE ID = emp.ID;
抛出您看到的ORA-00904错误。您还必须使update语句动态,例如:

EXECUTE IMMEDIATE 'UPDATE datacopy SET AGE_GROUP = :1 WHERE ID = :2' USING cust_age, emp.ID;
但是游标查询也会有问题,因为在运行时,它不再与编译时的表定义匹配-因此
SELECT*
现在返回的列比预期的多。(由此产生的错误是ORA-00932。)

您可以使整个游标循环成为动态的,但由于您只使用ID列,因此不需要-只需选择该特定列,而不是
*
。当然,您应该只在所有代码中选择所需的列

因此,要使其发挥作用,您可以:

DECLARE
    cust_age string(10);
    cust_inc string(10);
    cust_status string(10);
BEGIN
    EXECUTE IMMEDIATE 'ALTER TABLE DATACOPY ADD(AGE_GROUP VARCHAR2(10))';
    FOR emp IN (SELECT ID
                FROM datacopy) LOOP
        cust_age := get_group_age(emp.ID);
        cust_inc := get_income_level(emp.ID);
        cust_status := fix_status(emp.ID);
        EXECUTE IMMEDIATE 'UPDATE datacopy SET AGE_GROUP = :cust_age WHERE ID = :id'
          USING cust_age, emp.ID;
        UPDATE datacopy SET INCOME_LEVEL = cust_inc WHERE ID = emp.ID;
        UPDATE datacopy SET MARITAL_STATUS = cust_status WHERE ID = emp.ID;
        COMMIT;
    END LOOP;
END;
/
不过,这段代码还有许多其他问题。使用
string(10)
作为局部变量的数据类型不是很Oracle-y,而且它们实际上可能不是字符串-您可以对表中已经存在的列使用
%type
。您不应该在循环内提交。您正在对同一行进行三次单独的更新,这似乎是浪费,因为您可以使用一条动态语句同时设置所有三列值:

EXECUTE IMMEDIATE 'UPDATE datacopy SET AGE_GROUP = :cust_age,'
  || ' INCOME_LEVEL = :cust_inc,'
  || ' MARITAL_STATUS = :cust_status'
  || ' WHERE ID = :id'
  USING cust_age, cust_inc, cust_status, emp.ID;
当然,将
ALTER
作为简单的SQL语句在PL/SQL块之前执行会更简单,而不是在PL/SQL块内部执行

不过,看起来您根本不需要PL/SQL,也不需要逐个循环行;您可以在静态更改后执行单个静态更新:

ALTER TABLE DATACOPY ADD(AGE_GROUP VARCHAR2(10));

UPDATE datacopy SET AGE_GROUP = get_group_age(ID),
  INCOME_LEVEL = get_income_level(ID),
  MARITAL_STATUS = fix_status(ID);

正如@Maxim所说,在解析PL/SQL块时,表中没有
AGE\u GROUP
列,因此

UPDATE datacopy SET AGE_GROUP = cust_age WHERE ID = emp.ID;
抛出您看到的ORA-00904错误。您还必须使update语句动态,例如:

EXECUTE IMMEDIATE 'UPDATE datacopy SET AGE_GROUP = :1 WHERE ID = :2' USING cust_age, emp.ID;
但是游标查询也会有问题,因为在运行时,它不再与编译时的表定义匹配-因此
SELECT*
现在返回的列比预期的多。(由此产生的错误是ORA-00932。)

您可以使整个游标循环成为动态的,但由于您只使用ID列,因此不需要-只需选择该特定列,而不是
*
。当然,您应该只在所有代码中选择所需的列

因此,要使其发挥作用,您可以:

DECLARE
    cust_age string(10);
    cust_inc string(10);
    cust_status string(10);
BEGIN
    EXECUTE IMMEDIATE 'ALTER TABLE DATACOPY ADD(AGE_GROUP VARCHAR2(10))';
    FOR emp IN (SELECT ID
                FROM datacopy) LOOP
        cust_age := get_group_age(emp.ID);
        cust_inc := get_income_level(emp.ID);
        cust_status := fix_status(emp.ID);
        EXECUTE IMMEDIATE 'UPDATE datacopy SET AGE_GROUP = :cust_age WHERE ID = :id'
          USING cust_age, emp.ID;
        UPDATE datacopy SET INCOME_LEVEL = cust_inc WHERE ID = emp.ID;
        UPDATE datacopy SET MARITAL_STATUS = cust_status WHERE ID = emp.ID;
        COMMIT;
    END LOOP;
END;
/
不过,这段代码还有许多其他问题。使用
string(10)
作为局部变量的数据类型不是很Oracle-y,而且它们实际上可能不是字符串-您可以对表中已经存在的列使用
%type
。您不应该在循环内提交。您正在对同一行进行三次单独的更新,这似乎是浪费,因为您可以使用一条动态语句同时设置所有三列值:

EXECUTE IMMEDIATE 'UPDATE datacopy SET AGE_GROUP = :cust_age,'
  || ' INCOME_LEVEL = :cust_inc,'
  || ' MARITAL_STATUS = :cust_status'
  || ' WHERE ID = :id'
  USING cust_age, cust_inc, cust_status, emp.ID;
当然,将
ALTER
作为简单的SQL语句在PL/SQL块之前执行会更简单,而不是在PL/SQL块内部执行

不过,看起来您根本不需要PL/SQL,也不需要逐个循环行;您可以在静态更改后执行单个静态更新:

ALTER TABLE DATACOPY ADD(AGE_GROUP VARCHAR2(10));

UPDATE datacopy SET AGE_GROUP = get_group_age(ID),
  INCOME_LEVEL = get_income_level(ID),
  MARITAL_STATUS = fix_status(ID);