Dropping constraints in a PL/SQL loop - oracle

I get following error when I am attempting to disable constraints from hr.employees table
Error:
Error report -
ORA-02250: missing or invalid constraint name
ORA-06512: at line 14
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.
Following is the code
DECLARE
CURSOR C1 IS SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE TABLE_NAME ='EMPLOYEES';
v_con_name VARCHAR2(20);
SQL_STATMENT VARCHAR2(100);
BEGIN
SQL_STATMENT := 'ALTER TABLE HR.EMPLOYEES DISABLE CONSTRAINT :A';
OPEN C1;
LOOP
FETCH C1 INTO v_con_name;
EXIT WHEN C1%NOTFOUND;
EXECUTE IMMEDIATE SQL_STATMENT USING v_con_name;
DBMS_OUTPUT.PUT_LINE(v_con_name);
END LOOP;
CLOSE C1;
END;
/
When I comment following line
EXECUTE IMMEDIATE SQL_STATMENT USING v_con_name;
Scripts execute successfully and provide following results
EMP_LAST_NAME_NN
EMP_EMAIL_NN
EMP_HIRE_DATE_NN
EMP_JOB_NN
EMP_SALARY_MIN
EMP_EMAIL_UK
EMP_EMP_ID_PK
EMP_DEPT_FK
EMP_JOB_FK
EMP_MANAGER_FK
PL/SQL procedure successfully completed.
Hence I understand that the cursor construct is fetching the desired constraints name and also outside of this plsql block, I could successfully alter employees table by disabling these constraints.
Please note that I have logged in as HR schema in Oracle 11g R2 XE database
I am not sure why I am getting the missing or invalid constraint name.. thanks to help me here.

You can't use bind variables for the names of database objects (or for DDL in general). You will need to build the entire ALTER statement by concatenating the name. Try something like this:
declare
k_tablename constant user_constraints.table_name%type := 'EMPLOYEES';
begin
for r in (
select constraint_name
, 'alter table ' || c.table_name || ' disable constraint ' || c.constraint_name as sql_statement
from user_constraints c
where table_name = k_tablename
)
loop
execute immediate r.sql_statement;
dbms_output.put_line('Disabled constraint ' || k_tablename || '.' || r.constraint_name);
end loop;
end;
/

Why don't you use this script to generate the DISABLE script?
SELECT 'ALTER TABLE '||OWNER||'.'||TABLE_NAME||' DISABLE CONSTRAINT '||CONSTRAINT_NAME||';' STMNT
FROM DBA_CONSTRAINTS
WHERE
R_CONSTRAINT_NAME IN
(SELECT CONSTRAINT_NAME
FROM DBA_CONSTRAINTS
WHERE CONSTRAINT_TYPE IN ('P','U')
AND OWNER = 'HR'
AND TABLE_NAME IN
(
'EMPLOYEES'
));

Somewhat simpler (& working) then the original attempt:
SQL> create table test (id number constraint pk_test primary key,
2 ime varchar2(20) constraint ch_ime check (ime in ('little', 'foot')));
Table created.
SQL>
SQL> begin
2 for c1 in (select table_name, constraint_name
3 from user_constraints
4 where table_name = 'TEST')
5 loop
6 execute immediate 'alter table ' || c1.table_name ||
7 ' disable constraint ' || c1.constraint_name;
8 end loop;
9 end;
10 /
PL/SQL procedure successfully completed.
SQL> select constraint_name, status From user_constraints where table_name = 'TEST';
CONSTRAINT_NAME STATUS
------------------------------ --------
CH_IME DISABLED
PK_TEST DISABLED
SQL>

Related

How to use a variable to alter a constraint of a table in PL SQL?

I am trying to get the name of a constraint and then alter a table to remove the constraint. The constraint has not been named so I guess I have no other option. Here is what I tried:
DECLARE
the_variable VARCHAR2(20);
BEGIN
SELECT CONSTRAINT_NAME INTO the_variable
FROM all_constraints
WHERE table_name = 'MY_TABLE'
AND SEARCH_CONDITION_VC = 'format IN (''CSV'', ''PDF'')';
END;
The query above seems to work fine, but when I try to alter the table in this way:
ALTER TABLE SOME_TABLE DROP CONSTRAINT the_variable;
I get this error:
SQL Error [6550] [65000]: ORA-06550: line 14, column 1:
PLS-00103: Encountered the symbol "ALTER"
You can't perform DDL like that; has to be dynamic SQL. Here's an example - you need what's written in line #9:
SQL> create table my_table (id number primary key);
Table created.
SQL> declare
2 the_variable varchar2(30);
3 begin
4 select constraint_name
5 into the_variable
6 from all_constraints
7 where table_name = 'MY_TABLE';
8
9 execute immediate 'alter table my_table drop constraint ' || the_variable;
10 end;
11 /
PL/SQL procedure successfully completed.
SQL> select count(*) from all_constraints where table_name = 'MY_TABLE';
COUNT(*)
----------
0
SQL>

Create procedure in oracle DB for finding and deleting foreign key constraints for specific tables

I am new to Oracle, I am trying to write a procedure in Oracle to delete foreign key constraints for a table. I have already done this for MySQL and its working. I am not sure with the syntax, apologies for that, but my query is working If I run it individually. I want to do the same thing(removing foreign key constraints) for multiple tables and don't want to write queries multiple times. hence first I am finding the foreign keys associated with that table , storing them in cursor and later removing all of the foreign keys by creating and executing drop constraints query associated with that table. following code is giving multiple errors to me.
CREATE OR REPLACE PROCEDURE removeConstraintsForTable(vTableName IN varchar2) IS
BEGIN
cName VARCHAR(2048);
sql_stmt VARCHAR2(2048);
CURSOR cur IS
SELECT DISTINCT CONSTRAINT_NAME
FROM ALL_CONSTRAINTS WHERE OWNER= sys_context('userenv','current_schema')
AND TABLE_NAME = vTableName AND CONSTRAINT_TYPE='R';
BEGIN
OPEN cur;
LOOP
FETCH cur INTO cName;
EXIT WHEN cur%notfound;
sql_stmt := CONCAT(CONCAT(CONCAT('ALTER TABLE ',vTableName),CONCAT(' DROP FOREIGN KEY ',cName)),';');
SELECT sql_stmt FROM dual;
INSERT INTO TEMP(Name) VALUES(sql_stmt);
COMMIT;
END LOOP;
END
/
CALL removeConstraintsForTable('table1');
CALL removeConstraintsForTable('table2');
CALL removeConstraintsForTable('table3');
CALL removeConstraintsForTable('table4');
COMMIT;
You have an extra BEGIN right at the start of your procedure, and the final END is missing a semicolon. You shouldn't really be using VARCHAR, and you could declare the cName variable using the data dictionary anyway; however an implicit loop will be simpler, as will using the concatenation operator || instead of nested CONCAT() calls, and the generated statement should not end in a semicolon:
create or replace procedure removeconstraintsfortable(p_table_name in varchar2) is
sql_stmt varchar2(2048);
begin
for rec in (
select owner, constraint_name
from all_constraints
where owner = sys_context('userenv','current_schema')
and table_name = p_table_name
and constraint_type = 'R'
)
loop
sql_stmt := 'ALTER TABLE "' || rec.owner || '"."' || p_table_name || '"'
|| ' DROP CONSTRAINT "' || rec.constraint_name || '"';
insert into temp(name) values(sql_stmt);
end loop;
commit;
end;
/
As pointed out in comments, the generated statement should be drop constraint.
I'm not sure why you're inserting into a table or where you execute the statement, but you can do it all in one if you prefer:
create or replace procedure removeconstraintsfortable(p_table_name in varchar2) is
sql_stmt varchar2(2048);
begin
for rec in (
select owner, constraint_name
from all_constraints
where owner = sys_context('userenv','current_schema')
and table_name = p_table_name
and constraint_type = 'R'
)
loop
sql_stmt := 'ALTER TABLE "' || rec.owner || '"."' || p_table_name || '"'
|| ' DROP CONSTRAINT "' || rec.constraint_name || '"';
dbms_output.put_line(sql_stmt);
execute immediate sql_stmt;
end loop;
end;
/
The dbms_output call just shows you the generated statement(s), before execute immediate executes it, well, immediately.
Quick demo; very basic table set-up:
create table t42 (id number primary key);
create table t43 (id number references t42 (id));
select table_name, constraint_name, constraint_type
from all_constraints
where table_name in ('T42', 'T43');
TABLE_NAME CONSTRAINT_NAME C
------------------------------ ------------------------------ -
T43 SYS_C00138153 R
T42 SYS_C00138152 P
Then call the procedure which shows the generated statement:
set serveroutput on
exec removeConstraintsForTable('T43');
ALTER TABLE "STACKOVERFLOW"."T43" DROP CONSTRAINT "SYS_C00138153"
PL/SQL procedure successfully completed.
and then check the constraint has gone:
select table_name, constraint_name, constraint_type
from all_constraints
where table_name in ('T42', 'T43');
TABLE_NAME CONSTRAINT_NAME C
------------------------------ ------------------------------ -
T42 SYS_C00138152 P
I fixed a number of syntax issues for you. Try this.
CREATE OR REPLACE PROCEDURE removeConstraintsForTable(vTableName IN varchar2) IS
cName VARCHAR2(30); -- identifiers are max 30 chars
sql_stmt VARCHAR2(2048);
CURSOR cur IS
SELECT DISTINCT CONSTRAINT_NAME
FROM USER_CONSTRAINTS
WHERE TABLE_NAME = vTableName AND CONSTRAINT_TYPE='R';
BEGIN
OPEN cur;
LOOP
FETCH cur INTO cName;
EXIT WHEN cur%notfound;
sql_stmt := 'ALTER TABLE ' || vTableName || ' DROP CONSTRAINT ' || cName;
INSERT INTO RANGERADMIN1.TEMP(Name) VALUES(sql_stmt);
END LOOP;
COMMIT;
END removeConstraintsForTable;
/
call removeConstraintsForTable('table1');
call removeConstraintsForTable('table2');
call removeConstraintsForTable('table3');
call removeConstraintsForTable('table4');
-- COMMIT; -- not necessary

Oracle sql, alter constraint without specifying it's name

I would like to rename a constraint, in oracle database, without specify it's name, but with selecting it's name. I would like to do something like this:
ALTER TABLE O4Y_USER RENAME CONSTRAINT
(SELECT constraint_name
FROM user_constraints
WHERE table_name = 'O4Y_USER'
AND constraint_type = 'P'
) TO 'O4Y_USER_PK';
It is not working, I have the following error
The select alone, is working well, it returns the correct value. How is the correct syntax to do, to work the alter statement?
You can use dynamic SQL. Something like:
DECLARE
p_constraint_name VARCHAR2(30);
p_sql VARCHAR2(4000);
BEGIN
SELECT constraint_name
INTO p_constraint_name
FROM user_constraints
WHERE table_name = 'O4Y_USER'
AND constraint_type = 'P';
p_sql := 'ALTER TABLE O4Y_USER RENAME CONSTRAINT "'
|| p_constraint_name
|| '" TO ''O4Y_USER_PK''';
DBMS_OUTPUT.PUT_LINE( p_sql );
EXECUTE IMMEDIATE p_sql;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE( 'Constraint not found!' );
END;
/
And just the same method using SQL*Plus or similar command line tools.
SQL> create table t ( x int primary key );
Table created.
SQL>
SQL> col cname new_value x
SQL>
SQL> SELECT constraint_name cname
2 FROM user_constraints
3 WHERE table_name = 'T'
4 AND constraint_type = 'P';
CNAME
----------------------------------------------------------------------
SYS_C0068724
SQL>
SQL> ALTER TABLE t RENAME CONSTRAINT &&x to my_new_name;
old 1: ALTER TABLE t RENAME CONSTRAINT &&x to my_new_name
new 1: ALTER TABLE t RENAME CONSTRAINT SYS_C0068724 to my_new_name
Table altered.

Executing PL/SQL Begin/End procedure from Oracle JDBC thin driver

I am trying to create Oracle PL/SQL procedures and execute them via Oracle JDBC (thin driver). Here is the full PL/SQL script:
begin
for i in (select owner, constraint_name, table_name from all_constraints where owner = 'SCHEMA' and status = 'ENABLED') LOOP
execute immediate 'alter table SCHEMA.'||i.table_name||' disable constraint SCHEMA.'||i.constraint_name||'';
end loop;
end;
/
begin
for i in (select table_name from all_tables where owner = 'SCHEMA') LOOP
execute immediate 'truncate table SCHEMA.'||i.table_name||'';
end loop;
end;
/
begin
for i in (select owner, constraint_name, table_name from all_constraints where owner = 'SCHEMA' and status = 'DISABLED') LOOP
execute immediate 'alter table SCHEMA.'||i.table_name||' enable constraint SCHEMA.'||i.constraint_name||'';
end loop;
end;
/
In java I am splitting on '/' so each begin end block is executed in a separate statement. The java code to execute the statement is:
CallableStatement c = dbc.getConnection().prepareCall(sqlStatement);
c.executeUpdate();
I'm receiving the following error:
java.sql.SQLSyntaxErrorException: ORA-00933: SQL command not properly ended
ORA-06512: at line 3
How do I format this and execute the PL/SQL in JDBC?
Updated: To clarify, all three statements are executed without the '/' delimiter that is split on.
Updated: The oracle server is the following version: Oracle Database 11g Release 11.2.0.1.0 - 64bit Production
In the "enable /diable" constraint you shouldn't add the schema name (your'SCHEMA).
From the manual:
ALTER TABLE
Your example:
begin
for i in (select owner, constraint_name, table_name
from all_constraints
where owner = 'SCHEMA'
and status = 'ENABLED')
loop
execute immediate 'alter table SCHEMA.' || i.table_name ||
' disable constraint ' || i.constraint_name;
end loop;
end;
Test Query
select ac.constraint_name, ac.table_name, ac.status, ac.owner
from all_constraints ac
where ac.owner = 'HR'
and ac.constraint_name = 'EMP_SALARY_MIN'
Result
CONSTRAINT_NAME TABLE_NAME STATUS OWNER
------------------------------ ------------------------------ -------- --------------------------------------------------------------------------------
EMP_SALARY_MIN EMPLOYEES ENABLED HR
Correct dynamic sql
begin
execute immediate 'alter table HR.EMPLOYEES disable constraint EMP_SALARY_MIN';
end;
Previous query result
CONSTRAINT_NAME TABLE_NAME STATUS OWNER
------------------------------ ------------------------------ -------- --------------------------------------------------------------------------------
EMP_SALARY_MIN EMPLOYEES DISABLED HR

Any problem with renaming Oracle constraints directly in the user_constraint table?

Using Oracle 10g, I need to rename a bunch of FK constraints which all end in LITE to include an FK prefix.
My thinking was (I've ensured all names are short enough to accommodate the prefix):
DECLARE
v_name VARCHAR2(30 BYTE);
v_new_name VARCHAR2(30 BYTE);
CURSOR c1 is select CONSTRAINT name from user_constraints where constraint_type = 'R' and constraint_name like '%_LITE';
BEGIN
OPEN c1;
LOOP
FETCH c1 into v_name;
EXIT when c1%NOTFOUND;
v_new_name:= 'FK_' || v_name;
update user_constraints SET constraint_name = v_new_name where constraint_name = v_name;
END LOOP;
close c1;
END;
Any reason why that would be unsafe and I should have to create alter table statements instead?
USER_CONSTRAINTS is a view, you cannot update it as a normal user. EDIT: Even SYS cannot do that, and doing updates on the data dictionary seems like an incredibly bad idea to me.
Better use ALTER TABLE xxx RENAME CONSTRAINT yyy TO zzz;
As ammoQ says, don't even think about doing that! This is the equivalent code using ALTER TABLE:
BEGIN
FOR r IN (select constraint_name
from user_constraints
where constraint_type = 'R'
and constraint_name like '%_LITE'
)
LOOP
EXECUTE IMMEDIATE 'ALTER TABLE ' || r.table_name
|| ' RENAME CONSTRAINT ' || r.constraint_name
|| ' TO FK_' ||v_new_name;
END LOOP;
END;

Resources