一个警告
如果您实际上是在尝试为架构中每个表中的每个列替换一个字符串值,请注意这至少需要几个小时。
除了免责声明之外,类似的脚本在很多情况下都非常有用(可能会更改列名,可能会执行大量数据清理,或者从元数据表创建表)。
一般方法
基本上,您需要:
- 循环遍历目标模式中的每个表
- 对于每个表,遍历每一
VARCHAR2
列
- 对于每一列,生成一条
UPDATE
语句并执行它
UPDATE
更智能的解决方案只为每个表生成一个语句。您的解决方案将:
- 循环遍历目标模式中的每个表
UPDATE
对于每个表,生成语句的第一部分直到SET
子句
- 对于每一列,将子句的一部分附加
SET
到您的语句中
- 执行你的声明
Oracle 10g/11g 的示例代码,使用众所周知的 HR 模式:
每列一个 UPDATE 语句
DECLARE
schemaName VARCHAR2(30) := 'HR';
stmt VARCHAR2(32767); -- on 11g, use CLOB
BEGIN
FOR tr IN (
SELECT t.OWNER, t.TABLE_NAME
FROM ALL_TABLES t
WHERE t.OWNER = schemaName
ORDER BY 1, 2
)
LOOP
FOR cr IN (
SELECT c.COLUMN_NAME
FROM ALL_TAB_COLUMNS c
WHERE c.OWNER = tr.OWNER AND c.TABLE_NAME = tr.TABLE_NAME
AND c.DATA_TYPE = 'VARCHAR2'
ORDER BY 1
)
LOOP
stmt := 'UPDATE '||tr.OWNER||'.'||tr.TABLE_NAME
||' SET '||cr.COLUMN_NAME||' = REPLACE('||cr.COLUMN_NAME||', ''j'', ''b'')';
DBMS_OUTPUT.PUT_LINE(stmt||';'); -- useful for debugging
EXECUTE IMMEDIATE stmt;
END LOOP;
END LOOP;
END;
/
每个表一个 UPDATE 语句
您可以尝试更聪明一点,UPDATE
对表中的所有列只使用一条语句。注意不要溢出stmt
变量。
DECLARE
schemaName VARCHAR2(30) := 'HR';
stmt VARCHAR2(32767); -- on 11g, use CLOB
do_update BOOLEAN;
BEGIN
FOR tr IN (
SELECT t.OWNER, t.TABLE_NAME
FROM ALL_TABLES t
WHERE t.OWNER = schemaName
ORDER BY 1, 2
)
LOOP
do_update := FALSE;
stmt := 'UPDATE '||tr.OWNER||'.'||tr.TABLE_NAME||' SET ';
FOR cr IN (
SELECT c.COLUMN_NAME
FROM ALL_TAB_COLUMNS c
WHERE c.OWNER = tr.OWNER AND c.TABLE_NAME = tr.TABLE_NAME
AND c.DATA_TYPE = 'VARCHAR2'
ORDER BY 1
)
LOOP
do_update := TRUE;
stmt := stmt||cr.COLUMN_NAME||' = REPLACE('||cr.COLUMN_NAME||', ''j'', ''b''), ';
END LOOP;
IF do_update THEN
stmt := SUBSTR(stmt, 1, LENGTH(stmt) - 2); -- remove trailing ', '
DBMS_OUTPUT.PUT_LINE(stmt||';'); -- useful for debugging
EXECUTE IMMEDIATE stmt;
END IF;
END LOOP;
END;
/