如何解决SQL Error [946] [42000]: ORA-00946: missing TO keyword?

How to solve SQL Error [946] [42000]: ORA-00946: missing TO keyword?

我正在尝试更改所有 PK 约束名称。下面是我正在尝试的代码 运行:

BEGIN   
    FOR i IN (
    SELECT CONSTRAINT_NAME, CONSTRAINT_TYPE, TABLE_NAME
    FROM ALL_CONSTRAINTS
    WHERE OWNER = 'SOME_SCHEME'
    AND TABLE_NAME NOT LIKE 'flyway%'
    AND TABLE_NAME NOT LIKE 'BIN%'
    AND CONSTRAINT_TYPE = 'P')
    LOOP
    dbms_output.put_line(i.CONSTRAINT_NAME || i.table_name);
    EXECUTE IMMEDIATE 'ALTER TABLE i.table_name rename constraint i.constraint_name to i.table_name || ''_PK''';
    END LOOP;           
    END;

我收到以下错误:

SQL Error [946] [42000]: ORA-00946: missing TO keyword
ORA-06512: at line 17
ORA-06512: at line 17

为什么没有却说TO不见了? 如何解决这个问题?

如果在执行之前使用 dbms_output 显示语句,您会发现它的格式不正确;无论 table 和约束是什么,您当前尝试执行的语句都是:

ALTER TABLE i.table_name rename constraint i.constraint_name to i.table_name || '_PK'

i.* 部分不是变量或值,它们实际上是那些字符串。 运行 当然,该语句手动得到相同的错误。

您需要将循环变量值连接到语句中;您还需要指定所有者,因为您正在查看 all_tables,您不妨引用名称:

DECLARE
  l_stmt varchar2(4000);
BEGIN  
  FOR ... 
  LOOP
    dbms_output.put_line(i.CONSTRAINT_NAME || i.table_name);
    l_stmt := 'ALTER TABLE SOME_SCHEME."' || i.table_name || '"'
      || ' rename constraint "' || i.constraint_name || '"'
      || ' to "' || i.table_name || '_PK"';
    dbms_output.put_line(l_stmt);
    EXECUTE IMMEDIATE l_stmt;
  END LOOP;           
END;
/    

生成的内容更像:

ALTER TABLE SOME_SCHEME."SDO_DATUMS" rename constraint "DATUM_PRIM" to "SDO_DATUMS_PK"

db<>fiddle

我已经 hard-coded 您在循环查询中使用的 SOME_SCHEME 名称;您还可以通过将 OWNER 添加到 select 列表,然后将其连接起来(同样,引用过于谨慎)从查询本身获得它。或者在局部变量中设置它并在两个地方使用它,正如@MTO 在评论中建议的那样。

如果您只 运行 作为 SOME_SCHEME 用户,那么您可以改为查询 user_constraints

DECLARE
  l_stmt varchar2(4000);
BEGIN   
  FOR i IN (
    SELECT CONSTRAINT_NAME, CONSTRAINT_TYPE, TABLE_NAME
    FROM USER_CONSTRAINTS
    WHERE TABLE_NAME NOT LIKE 'flyway%' -- are these really quoted lower-case?
    AND TABLE_NAME NOT LIKE 'BIN%'
    AND CONSTRAINT_TYPE = 'P'
    AND CONSTRAINT_NAME != TABLE_NAME || '_PK'
  )
  LOOP
    l_stmt := 'ALTER TABLE "' || i.table_name || '"'
      || ' RENAME constraint "' || i.constraint_name || '"'
      || ' TO "' || i.table_name || '_PK"';
    dbms_output.put_line(l_stmt);
    EXECUTE IMMEDIATE l_stmt;
  END LOOP;           
END;
/

db<>fiddle 示例 tables,带引号和不带引号的标识符。

您可能还希望循环查询包括:

AND CONSTRAINT_NAME != TABLE_NAME || '_PK'

...这样您就不会触及已经具有您想要的名称模式的约束。