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
Related
I have this migration script;
ALTER TABLE table_name MODIFY (column_name NULL);
How do I make it idempotent?
Either you can use an exception handler:
DECLARE
CANNOT_MODIFIY_TO_NULL EXCEPTION;
PRAGMA EXCEPTION_INIT(CANNOT_MODIFIY_TO_NULL, -1451);
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE TABLE_NAME MODIFY (column_name NULL)';
exception
when CANNOT_MODIFIY_TO_NULL then
NULL;
END;
or check NULLABLE in view USER_TAB_COLUMNS:
DECLARE
CURSOR Cols IS
SELECT COLUMN_NAME
FROM USER_TAB_COLUMNS
WHERE TABLE_NAME = 'TABLE_NAME'
AND NULLABLE = 'N'
AND COLUMN_NAME = 'COLUMN_NAME';
BEGIN
FOR aCol IN Cols LOOP
EXECUTE IMMEDIATE 'ALTER TABLE TABLE_NAME MODIFY ('||aCol.COLUMN_NAME||' NULL)';
END LOOP;
END;
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
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.
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>
I'm trying to drop a schema in oracle 11g on our dev environment and I get back SQL Error: No more data to read from socket. There is no load on the schema as it's just a dev db. It's a small db without anything crazy going on. I see this error all the time. Restarting the instance sometimes resolves the problem. I can't seem to find any information that would point to a solution. Thanks!
I understand that this message often arises due to a bug. Also, when it appears an entry in your alert log and/or a trace file will contain more detail on what the error might actually be. To find your trace file for the session run:
select U_DUMP.value
|| '/'
|| DB_NAME.value
|| '_ora_'
|| V$PROCESS.SPID
|| nvl2(V$PROCESS.TRACEID, '_' || V$PROCESS.TRACEID, null)
|| '.trc'
"Trace File"
from V$PARAMETER U_DUMP
cross join V$PARAMETER DB_NAME
cross join V$PROCESS
join V$SESSION
on V$PROCESS.ADDR = V$SESSION.PADDR
where U_DUMP.NAME = 'user_dump_dest'
and DB_NAME.NAME = 'db_name'
and v$session.audsid=sys_context('userenv','sessionid');
A dba at my company gave me this one. It's
CREATE OR REPLACE PROCEDURE "SYS"."DROP_SCHEMA_FAST" (pSchema IN
VARCHAR2)
IS
cnt NUMBER(5) := 0;
sql1 varchar2(4000);
x PLS_INTEGER;
--disable constraints:
cursor cur1 is select 'alter table ' || OWNER ||'.'||table_name||' disable constraint '||constraint_name sql2
from all_constraints where owner=pSchema and status='ENABLED'
and table_name not like 'BIN$%' and constraint_name not like 'SYS_%' and constraint_name not like '%PK%';
cursor cur2 is select 'alter table ' || OWNER ||'.'||table_name||' disable constraint '||constraint_name sql2
from all_constraints where owner=pSchema and status='ENABLED'
and table_name not like 'BIN$%' and constraint_name not like 'SYS_%';
--truncate all tables:
cursor cur3 is select 'truncate table ' || OWNER ||'.'||table_name sql2 from all_tables where owner=pSchema
and table_name not like 'BIN$%';
BEGIN
SELECT COUNT(*) INTO cnt FROM dba_users WHERE UPPER(username) = UPPER(pSchema);
IF (cnt <= 0) THEN
RETURN;
END IF;
sql1 := 'ALTER USER ' || UPPER(pSchema) || ' ACCOUNT LOCK';
EXECUTE IMMEDIATE sql1;
--disable constraints:
FOR ao_rec IN cur1 LOOP
EXECUTE IMMEDIATE ao_rec.sql2;
END LOOP;
FOR ao_rec IN cur2 LOOP
EXECUTE IMMEDIATE ao_rec.sql2;
END LOOP;
--truncate all tables:
FOR ao_rec IN cur3 LOOP
EXECUTE IMMEDIATE ao_rec.sql2;
END LOOP;
--drop schema:
sql1 := 'DROP USER ' || UPPER(pSchema) || ' CASCADE';
EXECUTE IMMEDIATE sql1;
exception when others then null;
END;
Also had this problem, got fixed by setting "PLScope identifiers:" to "None" in Tools->Preferences ->Database->PL/SQL Compiler