Как сказал @Maxim, в момент разбора блока PL / SQL в таблице нет столбца AGE_GROUP
, поэтому
UPDATE datacopy SET AGE_GROUP = cust_age WHERE ID = emp.ID;
выдает ошибку ORA-00904, которую вы видите. Вы должны сделать это обновление также динамическим, например ::10000
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 или циклический переход по строкам; Вы можете сделать одно статическое обновление после статического изменения:
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);