alter table script in oracle based on select condition - sql

I need to modify a table to remove the primary key constraint, the only problem is the table is generated by another system and I don't have the constraint name. So as a workaround I have created the following script which I thought should work but it's not, so can anyone please help me to write another script which will work.
ALTER TABLE temp
MODIFY CONSTRAINT (select constraint_name
FROM all_constraints
WHERE owner like '%tempUser%' and
table_name like '%temp%' and
constraint_type = 'P'
)
DISABLE;
I am getting following error when trying to run.
SQL Error: ORA-14006: invalid partition name
14006. 00000 - "invalid partition name"
*Cause: a partition name of the form is
expected but not present.
*Action: enter an appropriate partition name.
I tried following code based on suggested link and it run without any error but it does not remove the constraint.
BEGIN
FOR c IN
(SELECT c.owner, c.table_name, c.constraint_name
FROM all_constraints c
where owner like '%tempUser%' and table_name like '%temp%' and constraint_type = 'P')
LOOP
dbms_utility.exec_ddl_statement('alter table ' || c.table_name || ' modify CONSTRAINT ' || c.constraint_name || ' disable ');
END LOOP;
END;
/

You could use dynamic SQL to solve this. First find the name of your constraint and then create dynamic code to disable it.
Have a look at Disable all table constraints in Oracle, which is similar

Related

Rebuilding an index, without knowing the index name (SQL)

What is the correct way to rebuild an index of a specific constraint, without knowing the index name, since it might different between environments.
In this case, prefer not knowing the index name (existing condition), and not renaming it first.
ALTER INDEX (select index_name from user_constraints where constraint_name = upper('constraint123')) REBUILD;
I tried casting, string, as is... and getting the following error
ORA-00953: missing or invalid index name
ALTER INDEX (select index_name from user_constraints where constraint_name = 'constraint123') REBUILD
Any time you don't know an object name (table name, column name, etc..) you have to use dynamic SQL, and that requires PL/SQL. Here's how you would do it:
CREATE OR REPLACE PROCEDURE p_rebuild_constraint_index (in_constraint_name IN varchar2)
AS
var_index_name varchar2(128);
BEGIN
SELECT MAX(index_name)
INTO var_index_name
FROM user_constraints
WHERE constraint_name = in_constraint_name;
IF var_index_name IS NOT NULL
THEN
EXECUTE IMMEDIATE 'ALTER INDEX "'||var_index_name||'" REBUILD';
END IF;
END;
Then simply call it:
BEGIN p_rebuild_constraint_index('CONSTRAINT123'); END;

How to temporarily disable all constraints of a schema in postgresql?

I need to temporarily disable all constraints and triggers of a schema in order to anonymize data in several tables. As there are dependencies between tables, I prefer to disable everything and once the anonymization treatment is over I can enable all constraints and triggers one more time.
I tried SET FOREIGN_KEY_CHECKS=0; and I got this error:
ERROR: unrecognized configuration parameter "foreign_key_checks"
SQL state: 42704
I've been reading a lot about that and some people say this is not possible.
Do you know a way to do that?
Thank you!
To disable foreign keys and deferrable unique and primary key constraints for a table, you can use
ALTER TABLE ... DISABLE TRIGGER ALL;
To disable all such constraints for the duration of a database session, you can
SET session_replication_role = replica;
Both tricks won't work for non-deferrable constraints and check constraints.
I found this solution,
I created a temporal table to keep all constraints definition:
CREATE TEMPORARY TABLE temp_constraints AS
SELECT conname constraintname, conrelid::regclass tablename, pg_get_constraintdef(oid) definition, contype
FROM pg_catalog.pg_constraint;
Then I drop all constraints:
DO $$
DECLARE constraint_name TEXT;
DECLARE constraint_table TEXT;
BEGIN
FOR constraint_name, constraint_table IN
SELECT constraintname , tablename FROM temp_constraints ORDER BY contype DESC
LOOP
EXECUTE 'ALTER TABLE ' || constraint_table || ' DROP CONSTRAINT IF EXISTS ' || constraint_name || ' CASCADE;';
END LOOP;
END $$;
And after anonymizing data I restore all constraints using the definitions in the temporal table and I drop the temporal table:
DO $$
DECLARE constraint_table TEXT;
DECLARE constraint_definition TEXT;
BEGIN
FOR constraint_table, constraint_definition IN
SELECT tablename, definition FROM temp_constraints ORDER BY contype DESC
LOOP
EXECUTE 'ALTER TABLE ' || constraint_table || ' ADD ' || constraint_definition || ';';
END LOOP;
DROP TABLE IF EXISTS temp_constraints;
END $$;
I hope this can help someone else. Thank you!

Is it possible to use select query inside alter statement in oracle?

I have the following query which will delete the constraint as i did not know the constraint name, i am getting it from select query by specifying table name and column name.
ALTER TABLE <CHILD_TABLE_NAME>
DROP CONSTRAINT in (SELECT
CONS.CONSTRAINT_NAME
FROM USER_CONSTRAINTS CONS
LEFT JOIN USER_CONS_COLUMNS COLS ON COLS.CONSTRAINT_NAME = CONS.CONSTRAINT_NAME
LEFT JOIN USER_CONSTRAINTS CONS_R ON CONS_R.CONSTRAINT_NAME = CONS.R_CONSTRAINT_NAME
LEFT JOIN USER_CONS_COLUMNS COLS_R ON COLS_R.CONSTRAINT_NAME = CONS.R_CONSTRAINT_NAME
WHERE CONS.CONSTRAINT_TYPE = 'R'
AND COLS.COLUMN_NAME='<COLUMN_NAME>'
AND CONS.TABLE_NAME = '<CHILD_TABLE_NAME>')
when i am runnning above query , getting the below error in pl/sql developer
ORA-02250:missing or invalid constraint name
You should check out "Oracle Database SQL Language Reference" to see if "ALTER TABLE" command has in its syntax the ability to have a subquery in it, which it doesn't. Example --> http://docs.oracle.com/database/121/SQLRF/statements_3001.htm#SQLRF01001
"alter table" command, "drop_constraint_clause" example from the provided link
To sum up all, the answer is no you cannot have a subquery specified in a "alter table" command.
What you can do is do it with dynamic SQL as #J. Chomel specified.
Example :
BEGIN
FOR i in (<<YOUR SELECT>>)
LOOP
EXECUTE IMMEDIATE 'ALTER TABLE '||i.TABLE_NAME||' DROP CONSTRAINT '||i.CONSTRAINT_NAME;
END LOOP;
END;

Oracle PL SQL disable all constraints of database tables

I try to disable all constraint of all database tables. The database is named "database_test". The performance is not a problem.
I wrote a pl/sql script which give me all constraints with the table.
My problem is : when I run the script SQL developper say me "ORA-00972: identifier is too long". But I use only the fields already defined in the database.
CREATE OR REPLACE PROCEDURE DISPLAY_CONSTRAINT_DATABASE AS
BEGIN
FOR i IN (SELECT DISTINCT OWNER, OBJECT_NAME FROM ALL_OBJECTS WHERE OBJECT_TYPE = 'TABLE' AND OWNER = 'DB_NAME')
LOOP
FOR j IN (SELECT CONSTRAINT_NAME FROM ALL_CONSTRAINTS WHERE owner = i.OWNER AND table_name = i.OBJECT_NAME AND CONSTRAINT_TYPE='R')
LOOP
dbms_utility.exec_ddl_statement('alter table "DB_NAME.' || i.OBJECT_NAME || ' DISABLE CONSTRAINT ' || j.CONSTRAINT_NAME);
END LOOP;
END LOOP;
END DISPLAY_CONSTRAINT_DATABASE;
Your double quotes are wrong. You are generating SQL statements like this:
alter table "DB_NAME.FOOBAR disable constraint some_constraint;
Which misses the second double quote (my guess is that you probably wanted to put the second quote after the table name which would have been wrong as well).
You need to put each part of the identifier in quotes, not the whole thing:
alter table "DB_NAME"."FOOBAR" disable constraint some_constraint;
I also don't see the necessity to use dbms_sql:
execute immediate 'alter table "DB_NAME"."' || i.OBJECT_NAME || '" DISABLE CONSTRAINT ' || j.CONSTRAINT_NAME;
To avoid having to repeat the owner, I would actually change the statement to:
execute immediate 'alter table "'||j.owner||'"."' || i.OBJECT_NAME || '" DISABLE CONSTRAINT ' || j.CONSTRAINT_NAME;
Thus you only need to "hard-code" the owner name once in the procedure.

How to check if a column exists before adding it to an existing table in PL/SQL?

How do I add a simple check before adding a column to a table for an oracle db? I've included the SQL that I'm using to add the column.
ALTER TABLE db.tablename
ADD columnname NVARCHAR2(30);
All the metadata about the columns in Oracle Database is accessible using one of the following views.
user_tab_cols; -- For all tables owned by the user
all_tab_cols ; -- For all tables accessible to the user
dba_tab_cols; -- For all tables in the Database.
So, if you are looking for a column like ADD_TMS in SCOTT.EMP Table and add the column only if it does not exist, the PL/SQL Code would be along these lines..
DECLARE
v_column_exists number := 0;
BEGIN
Select count(*) into v_column_exists
from user_tab_cols
where upper(column_name) = 'ADD_TMS'
and upper(table_name) = 'EMP';
--and owner = 'SCOTT --*might be required if you are using all/dba views
if (v_column_exists = 0) then
execute immediate 'alter table emp add (ADD_TMS date)';
end if;
end;
/
If you are planning to run this as a script (not part of a procedure), the easiest way would be to include the alter command in the script and see the errors at the end of the script, assuming you have no Begin-End for the script..
If you have file1.sql
alter table t1 add col1 date;
alter table t1 add col2 date;
alter table t1 add col3 date;
And col2 is present,when the script is run, the other two columns would be added to the table and the log would show the error saying "col2" already exists, so you should be ok.
Or, you can ignore the error:
declare
column_exists exception;
pragma exception_init (column_exists , -01430);
begin
execute immediate 'ALTER TABLE db.tablename ADD columnname NVARCHAR2(30)';
exception when column_exists then null;
end;
/
Normally, I'd suggest trying the ANSI-92 standard meta tables for something like this but I see now that Oracle doesn't support it.
-- this works against most any other database
SELECT
*
FROM
INFORMATION_SCHEMA.COLUMNS C
INNER JOIN
INFORMATION_SCHEMA.TABLES T
ON T.TABLE_NAME = C.TABLE_NAME
WHERE
C.COLUMN_NAME = 'columnname'
AND T.TABLE_NAME = 'tablename'
Instead, it looks like you need to do something like
-- Oracle specific table/column query
SELECT
*
FROM
ALL_TAB_COLUMNS
WHERE
TABLE_NAME = 'tablename'
AND COLUMN_NAME = 'columnname'
I do apologize in that I don't have an Oracle instance to verify the above. If it does not work, please let me know and I will delete this post.
To check column exists
select column_name as found
from user_tab_cols
where table_name = '__TABLE_NAME__'
and column_name = '__COLUMN_NAME__'
Reference link