1

我正在尝试遍历 oracle DB 中的每个表,并查找和替换字符串值。我想为整个数据库中的所有条目查找字符串值的所有实例,将其替换为另一个字符串值。我很接近,但由于某种原因,我的代码没有正确响应。

DECLARE
   CURSER all_tables IS
      SELECT table_name FROM all_tables;
   v_count NUMBER;
BEGIN
   FOR host IN all_tables LOOP
      SELECT REPLACE('jack','j','b') "Changes"
         FROM host
   END LOOP;
END;
4

1 回答 1

3

一个警告

如果您实际上是在尝试为架构中每个表中的每个列替换一个字符串值,请注意这至少需要几个小时。

除了免责声明之外,类似的脚本在很多情况下都非常有用(可能会更改列名,可能会执行大量数据清理,或者从元数据表创建表)。

一般方法

基本上,您需要:

  1. 循环遍历目标模式中的每个表
  2. 对于每个表,遍历每一VARCHAR2
  3. 对于每一列,生成一条UPDATE语句并执行它

UPDATE更智能的解决方案只为每个表生成一个语句。您的解决方案将:

  1. 循环遍历目标模式中的每个表
  2. UPDATE对于每个表,生成语句的第一部分直到SET子句
  3. 对于每一列,将子句的一部分附加SET到您的语句中
  4. 执行你的声明

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;
/
于 2013-05-15T19:50:41.737 回答