2012-01-25 15 views
5

En una base de datos de Oracle tengo una clave externa, sin saber su nombre, solo el nombre de la columna y el nombre de la columna de referencia. Quiero escribir una secuencia de comandos SQL que debe caer esta clave externa si es que existe, por lo que este es el código que utilizo:soltar índice o restricción sin saber su nombre para Oracle

declare 
fName varchar2(255 char); 
begin 
SELECT x.constraint_name into fName FROM all_constraints x 
JOIN all_cons_columns c ON 
c.table_name = x.table_name AND c.constraint_name = x.constraint_name 
WHERE x.table_name = 'MY_TABLE_NAME' AND x.constraint_type = 'R' AND c.column_name ='MY_COLUMN_NAME'; 
end; 

La salida de este script es "bloque anónimo completado", por lo que se ha realizado correctamente, pero cuando agrego la parte caída:

declare 
fName varchar2(255 char); 
begin 
SELECT x.constraint_name into fName FROM all_constraints x 
JOIN all_cons_columns c ON 
c.table_name = x.table_name AND c.constraint_name = x.constraint_name 
WHERE x.table_name = 'MY_TABLE_NAME' AND x.constraint_type = 'R' AND c.column_name ='MY_COLUMN_NAME'; 
if (fName != '') THEN 
    alter table MY_TABLE_NAME drop constraint fName; 
end if; 
end; 

Entonces consigo éste:

Error report: ORA-06550: line 9, column 5: PLS-00103: Encountered the symbol "ALTER" when expecting one of the following:

begin case declare exit for goto if loop mod null pragma raise return select update while with << close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe 06550. 00000 - "line %s, column %s:\n%s" *Cause: Usually a PL/SQL compilation error. *Action:

Entonces, ¿puede alguien decirme cuál es el problema aquí?

También probé a poner todo en una función:

declare 
    function getFName return varchar2 is 
    fName varchar2(255 char); 
    begin 
    SELECT x.constraint_name into fName FROM all_constraints x 
    JOIN all_cons_columns c ON 
    c.table_name = x.table_name AND c.constraint_name = x.constraint_name 
    WHERE x.table_name = 'MY_TABLE_NAME' AND x.constraint_type = 'R' AND c.column_name ='MY_COLUMN_NAME'; 

    return fName; 
    end; 
begin 
    if getFName() != '' then 
    alter table all_events drop constraint getFName(); 
    end if; 
end; 

El resultado fue el mismo error causado por la declaración "alter table"

Este también no ayudó:

alter table all_events drop constraint 
    (SELECT x.constraint_name into fName FROM all_constraints x 
    JOIN all_cons_columns c ON 
    c.table_name = x.table_name AND c.constraint_name = x.constraint_name 
    WHERE x.table_name = 'MY_TABLE_NAME' AND x.constraint_type = 'R' AND c.column_name ='MY_COLUMN_NAME'); 

La salida fue:

Error report: SQL Error: ORA-02250: missing or invalid constraint name 02250. 00000 - "missing or invalid constraint name" *Cause: The constraint name is missing or invalid. *Action: Specify a valid identifier name for the constraint name.

Para un servidor sql (MS SQL) es tan fácil hacer esto. Simplemente declarando una variable con @ y la configuró, después de eso solo úsala. En Oracle no tengo idea de lo que no está funcionando ...

Respuesta

6

Su versión original es bastante buena, excepto que no se puede ejecutar directamente DDL en un bloque PL/SQL; más bien, hay que envolverlo en un EXECUTE IMMEDIATE:

execute immediate 'alter table MY_TABLE_NAME drop constraint "' || fName || '"'; 

Esto sería cierto incluso si el nombre de la restricción se conoce en tiempo de compilación, pero es doblemente cierto en su caso, ya que fName no es la restricción -name, sino más bien, una variable que contiene el nombre de restricción.

Además, este:

if (fName != '') THEN 

no es válida/significativo, ya que en Oracle '' significa NULL. Debe escribir

IF fName IS NOT NULL THEN 

en su lugar.

+0

Hey simplemente una cuestión adicional acerca de esto: Con esta instrucción de selección teórico me gustaría tener más de un nombre de restricción si una columna C1 de las referencias de la tabla A1 a C2 de la tabla A2 y referencias C1 a C3 de la tabla A3, entonces obtendría los nombres para C1-> C2 y C1-> C3, entonces la pregunta es ¿dónde puedo unir la información a qué columna soy referenciando? – radio

+0

@radio: On 'all_constraints',' (r_owner, r_constraint_name) 'es efectivamente una clave externa; puede volver a unirse a 'all_constraints' para obtener información sobre la (s) columna (s) referenciada (s). (Dentro de Oracle, una clave externa se implementa como una clave externa a * otra restricción *. Esto tiene sentido si se tiene en cuenta lo que el DBMS debe hacer para aplicar una restricción de clave externa.) – ruakh

+0

@radio: Por cierto, su preocupación "teórica" ​​me preocupa un poco, porque hay otros problemas más grandes con su código: por ejemplo, usa 'all_constraints' y' all_cons_columns' sin verificar 'owner' , y no verifica para asegurarse de que ''MY_COLUMN_NAME'' sea la única columna en la clave externa. Entonces, tu parte de código no es de propósito general. Asumía que planeabas usarlo en una circunstancia específica en la que tenías mucha otra información, pero por algún motivo, simplemente, faltabas el nombre de restricción. Si necesita un código de propósito general, tiene que arreglar muchas cosas. – ruakh

2

Esto es cómo abandonar todas las restricciones al escribir "R" para una columna:

begin 
    FOR rec IN (SELECT x.constraint_name fName FROM all_constraints x 
     JOIN all_cons_columns c ON 
     c.table_name = x.table_name AND c.constraint_name = x.constraint_name 
     WHERE x.table_name = 'MY_TABLE_NAME' AND x.constraint_type = 'R' AND c.column_name ='MY_COLUMN_NAME') 
    LOOP 
     EXECUTE IMMEDIATE 'ALTER TABLE MY_TABLE_NAME DROP CONSTRAINT "' || rec.fName || '"'; 
    END LOOP; 
end; 
Cuestiones relacionadas