【发布时间】:2019-12-03 13:42:00
【问题描述】:
问题
我正在尝试执行一些 DDL 语句来创建一个临时表,然后在 PL/SQL 中的游标上执行循环以将一些数据复制到新创建的临时表中,然后再执行一些 DDL 来进行一些最终调整复制数据后到表中。
但是,我最终得到了错误消息
SP2-0552: Bind variable "NEW" is not declared
在初始 DDL 之后没有任何内容(即循环中或之后的任何内容)都没有被执行。
奇怪的是,如果我一个接一个地执行语句(首先是 DDL,然后是循环,然后是剩余的 DDL)而不是使用 SQL Developer 执行单个批处理,它就像一个魅力。如果其他一切都失败了,这可能是最后的手段,但首选的解决方案是一次完成所有事情,所以我们可以只分发一个更新脚本供人们使用。我想知道问题是什么。
动机
我需要修改包含大量数据的表中的一些列(数百万行,可能有 30 列)。直接更改列会导致事务变得太大,因此我选择执行以下操作:
- 使用新列定义创建一个表。
- 复制数据,同时每几千个条目执行一次提交。
- 删除所有引用旧表的约束和索引。
- 放下旧桌子。
- 将新表重命名为旧表。
- 在新表上重新创建约束和索引。
最少的可重复样本
以下最小示例说明了上述步骤,但为简洁起见,我省略了任何索引和外键。
首先是应该迁移的表的定义。
-- This is the old table A.
CREATE TABLE TestA (
ID number not null,
Val varchar2(20 CHAR),
constraint PK_TestA primary key
(
ID
)
);
CREATE SEQUENCE SEQ_TestA
INCREMENT BY 1;
CREATE TRIGGER TRI_TestA
BEFORE INSERT ON TestA
FOR EACH ROW
BEGIN
SELECT SEQ_TestA.NEXTVAL
INTO :NEW.ID FROM DUAL;
EXCEPTION WHEN OTHERS THEN NULL;
END;
.
RUN;
-- Insert some test data.
INSERT INTO TestA (Val) VALUES ('Hello');
INSERT INTO TestA (Val) VALUES ('World');
INSERT INTO TestA (Val) VALUES ('Foo');
INSERT INTO TestA (Val) VALUES ('Bar');
commit;
然后是实际的迁移脚本:
-- Create the new table B with the new column definitions.
CREATE TABLE TestB (
ID number not null,
Val nvarchar2(50),
constraint PK_TestB primary key
(
ID
)
);
-- Copy data from A to B and commit every once in a while.
DECLARE
counter number := 0;
CURSOR migrationrows
IS
SELECT
ID,
Val
FROM TestA;
BEGIN
FOR migrationrow
IN migrationrows
LOOP
INSERT INTO TestB (
ID,
Val
)
VALUES
(
migrationrow.ID,
migrationrow.Val
);
counter := counter + 1;
IF counter > 2 THEN
commit;
counter := 0;
END IF;
END LOOP;
commit;
END;
-- Now get rid of the old A and make B the new A.
DROP TRIGGER TRI_TestA;
DROP TABLE TestA;
ALTER TABLE TestB RENAME TO TestA;
ALTER TABLE TestA RENAME CONSTRAINT PK_TestB TO PK_TestA;
CREATE TRIGGER TRI_TestA
BEFORE INSERT ON TestA
FOR EACH ROW
BEGIN
SELECT SEQ_TestA.NEXTVAL
INTO :NEW.ID FROM DUAL;
EXCEPTION WHEN OTHERS THEN NULL;
END;
.
RUN;
commit;
如果我从放置注释行的每个步骤中运行它,它就会起作用。但是如果我完全运行它,我会得到上面显示的错误。
【问题讨论】: