How to reset identity columns in Oracle (PL SQL) - sql

I need to write a script to reset all auto-incrementing fields in the database to 0.

I want to share the solution to the problem.
To get a list of table names, I do the following:
SELECT T.TABLE_NAME FROM ALL_TAB_COLUMNS C
INNER JOIN ALL_TABLES T ON C.OWNER = T.OWNER AND C.TABLE_NAME = T.TABLE_NAME
WHERE T.OWNER = 'SCHEME'
AND C.DATA_DEFAULT IS NOT NULL
Further in the loop, you can generate dynamic sql as follows:
ALTER TABLE TABLE_NAME
MODIFY ID
GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH 1);
And we execute the dynamic SQL line through EXECUTE IMMEDIATE.
Below is an example from my project:
PROCEDURE RESET_ALL_IDENTITY_COLUMNS IS
BEGIN
FOR TABLES_WITH_IDENTITY IN (SELECT T.TABLE_NAME FROM ALL_TAB_COLUMNS C
INNER JOIN ALL_TABLES T ON C.OWNER = T.OWNER AND C.TABLE_NAME = T.TABLE_NAME
WHERE T.OWNER = 'DZR'
AND C.DATA_DEFAULT IS NOT NULL)
LOOP
EXECUTE IMMEDIATE 'ALTER TABLE ' || TABLES_WITH_IDENTITY.TABLE_NAME || ' MODIFY ID GENERATED BY DEFAULT ' ||
'ON NULL AS IDENTITY (START WITH 1)';
END LOOP;
END;
Good luck :)

Related

How to rename a default constraint on Oracle?

I want to rename many constraints (PK, FK, ...etc. ) that have default names which start with 'SYS' to be able to insert the same data in other DB.
I found the following script that I changed to get what I want:
BEGIN
FOR cn IN (
SELECT constraint_name
FROM user_constraints
WHERE constraint_type = 'P'
AND table_name = 'SPECIALITE'
)
LOOP
EXECUTE IMMEDIATE 'ALTER TABLE ' || cn.table_name || ' RENAME CONSTRAINT ' || cn.constraint_name || ' TO PK_' || 'SPECIALITE';
END LOOP;
END;
This script works, but it seems a bit complicated for me, I wonder if it exists something like:
ALTER TABLE 'SPECIALITE' RENAME CONSTRANT (....)
The problem is I don't know the name of constraints, they have a default name, I know only tables where they are.
Is it possible?
As you already know, you need to run two queries.
select constraint_name from user_constraints
where table_name = <table_name> and constraint_type = 'P';
and with the constraint name in hand,
alter table <table_name> rename constraint <old_constr_name> to <new_constr_name>;
This will require copying the constraint name from the first query and pasting it into the second, in the proper place (<old_constr_name>).
If this was all, I wouldn't post an answer. But I remember something I read on AskTom some time ago - a clever way to avoid copying and pasting, using the COLUMN command in SQL*Plus. (This may also work in SQL Developer and Toad.) Something like this:
column constraint_name new_val c -- Note: no semicolon - this is SQL*Plus, not SQL
select constraint_name from user_constraints
where table_name = <table_name> and constraint_type = 'P';
alter table <table_name> rename constraint &c to <new_constr_name>;
If you need to change many PK constraint names, this will save some work. The constraint name returned by the SELECT query is saved in the "new_val" labeled "c" from the SQL*Plus COLUMN command, and it is used in the ALTER TABLE statement.
Add user_cons_columns view to your SQL so you can generate constraint names. Here is a quick and dirty example:
select 'ALTER TABLE ' || c.table_name || ' RENAME CONSTRAINT ' || c.constraint_name || ' TO ' || substr(c.constraint_type || '_' || c.table_name || '_' || replace(wm_concat(cc.column_name), ',', '_'), 0, 30) || ';'
from user_constraints c
join user_cons_columns cc on c.table_name = cc.table_name and c.constraint_name = cc.constraint_name
where c.constraint_name like 'SYS%'
group by c.table_name, c.constraint_name, c.constraint_type;
This SQL generates an executable script with commands like this:
ALTER TABLE TABLENAME RENAME CONSTRAINT SYS_xxxxxx TO C_TABLENAME_COLUMN;
Please note that I'm using undocumented wm_concat function. If you're using Oracle >= 11g consider using listagg instead.
If you don't have the constraint name, you can't do it directly. But you can easily generate the statement.
select 'ALTER TABLE ' || table_name || ' RENAME CONSTRAINT ' || constraint_name || ' TO PK_' || upper( table_name )
from user_constraints
where constraint_type = 'P'
and constraint_name like 'SYS%';
This select will list all tables with a constraint on its primary key that start by 'SYS'and rename it to PK_TABLE_NAME;
You just have to check if all statements looks ok for you and run them.
You also can use the generated column like this
select 'ALTER TABLE ' || table_name || ' RENAME CONSTRAINT ' || constraint_name || ' TO PK_' || upper( table_name )
from user_constraints
where constraint_type = 'P'
and generated = 'GENERATED NAME';
but you will have BIN tables and maybe other unwanted tables

Delete every inactive data SQL

I need to delete every data from every table in a specific schema that satisfy the condition to be inactive. Active/inactive value is a boolean that every table has this column.
How do I do this?
You can't just do this magically you need to write a query to create your query.
Something like this :
select distinct tablename from information_schema.columns where columnname = 'Active'
would give you a list of tables then just add that into a query that says
delete from <tablename> where active = 0
You can create a function to do that:
CREATE OR REPLACE FUNCTION delete_inactive_records()
RETURNS TEXT AS
$BODY$
DECLARE VTABLES RECORD;
VRESULT TEXT;
VNUM_ROWS INTEGER;
BEGIN
VRESULT = '';
FOR VTABLES IN (
select distinct table_schema || '.' || table_name as table_name
from information_schema.tables t
where exists (
select 1
from information_schema.columns c
where c.table_catalog = t.table_catalog
and c.table_schema = c.table_schema
and c.table_name = t.table_name
and c.column_name = 'active'
and t.table_catalog in ("<your_table_catalog1>", "<your_table_catalog2>", "<etc>")
)
order by 1
)
LOOP
RAISE NOTICE 'DELETING FROM %...', VTABLES.TABLE_NAME;
EXECUTE ('DELETE FROM ' || VTABLES.TABLE_NAME || ' WHERE active = 0');
get diagnostics vNUM_ROWS = ROW_COUNT;
VRESULT = VRESULT || vNUM_ROWS || ' records were deleted from ' || VTABLES.TABLE_NAME || chr(13);
END LOOP;
return VRESULT;
end;
$BODY$
LANGUAGE plpgsql VOLATILE;
And then call select delete_inactive_records(); any time you want to "clean-up" your tables!

Updating a column matching a specific pattern in all table in an oracle database

I need to update a column matching a specific pattern in all tables in an oracle database.
For example I have in all tables this column *_CID with is a foreign key to master table witch has a primary key CID
Thanks
You can use the naming convention and query all_tab_columns
declare
cursor c is
select table_owner , column_name, table_name from all_tab_columns where column_name like '%_CID';
begin
for x in c loop
execute immediate 'update ' || x.table_owner || '.' || x.table_name ||' set ' || x.column_name||' = 0';
end loop;
end;
If you have valid Fk's you can also use all_tab_constraints the fetch enabled FK's for your main table and fetch the columns name of the r_constraint_name.
I found a solution to my question:
BEGIN
FOR x IN (SELECT owner, table_name, column_name FROM all_tab_columns) LOOP
EXECUTE IMMEDIATE 'update ' || x.owner || '.' || x.table_name ||' set ' || x.column_name||' = 0 where '||x.column_name||' = 1';
END LOOP;
END;
thanks

How can I find which tables reference a given table in Oracle SQL Developer?

In Oracle SQL Developer, if I'm viewing the information on a table, I can view the constraints, which let me see the foreign keys (and thus which tables are referenced by this table), and I can view the dependencies to see what packages and such reference the table. But I'm not sure how to find which tables reference the table.
For example, say I'm looking at the emp table. There is another table emp_dept which captures which employees work in which departments, which references the emp table through emp_id, the primary key of the emp table. Is there a way (through some UI element in the program, not through SQL) to find that the emp_dept table references the emp table, without me having to know that the emp_dept table exists?
No. There is no such option available from Oracle SQL Developer.
You have to execute a query by hand or use other tool (For instance PLSQL Developer has such option). The following SQL is that one used by PLSQL Developer:
select table_name, constraint_name, status, owner
from all_constraints
where r_owner = :r_owner
and constraint_type = 'R'
and r_constraint_name in
(
select constraint_name from all_constraints
where constraint_type in ('P', 'U')
and table_name = :r_table_name
and owner = :r_owner
)
order by table_name, constraint_name
Where r_owner is the schema, and r_table_name is the table for which you are looking for references. The names are case sensitive
Be careful because on the reports tab of Oracle SQL Developer there is the option "All tables / Dependencies" this is from ALL_DEPENDENCIES which refers to "dependencies between procedures, packages, functions, package bodies, and triggers accessible to the current user, including dependencies on views created without any database links.". Then, this report have no value for your question.
To add this to SQL Developer as an extension do the following:
Save the below code into an xml file (e.g. fk_ref.xml):
<items>
<item type="editor" node="TableNode" vertical="true">
<title><![CDATA[FK References]]></title>
<query>
<sql>
<![CDATA[select a.owner,
a.table_name,
a.constraint_name,
a.status
from all_constraints a
where a.constraint_type = 'R'
and exists(
select 1
from all_constraints
where constraint_name=a.r_constraint_name
and constraint_type in ('P', 'U')
and table_name = :OBJECT_NAME
and owner = :OBJECT_OWNER)
order by table_name, constraint_name]]>
</sql>
</query>
</item>
</items>
Add the extension to SQL Developer:
Tools > Preferences
Database > User Defined Extensions
Click "Add Row" button
In Type choose "EDITOR", Location is where you saved the xml file above
Click "Ok" then restart SQL Developer
Navigate to any table and you should now see an additional tab next to SQL one, labelled FK References, which displays the new FK information.
Reference
http://www.oracle.com/technetwork/issue-archive/2007/07-jul/o47sql-086233.html
Replace [Your TABLE] with emp in the query below
select owner,constraint_name,constraint_type,table_name,r_owner,r_constraint_name
from all_constraints
where constraint_type='R'
and r_constraint_name in (select constraint_name
from all_constraints
where constraint_type in ('P','U')
and table_name='[YOUR TABLE]');
You may be able to query this from the ALL_CONSTRAINTS view:
SELECT table_name
FROM ALL_CONSTRAINTS
WHERE constraint_type = 'R' -- "Referential integrity"
AND r_constraint_name IN
( SELECT constraint_name
FROM ALL_CONSTRAINTS
WHERE table_name = 'EMP'
AND constraint_type IN ('U', 'P') -- "Unique" or "Primary key"
);
SQL Developer 4.1, released in May of 2015, added a Model tab which shows table foreign keys which refer to your table in an Entity Relationship Diagram format.
SELECT DISTINCT table_name,
constraint_name,
column_name,
r_table_name,
position,
constraint_type
FROM (SELECT uc.table_name,
uc.constraint_name,
cols.column_name,
(SELECT table_name
FROM user_constraints
WHERE constraint_name = uc.r_constraint_name) r_table_name,
(SELECT column_name
FROM user_cons_columns
WHERE constraint_name = uc.r_constraint_name
AND position = cols.position) r_column_name,
cols.position,
uc.constraint_type
FROM user_constraints uc
inner join user_cons_columns cols
ON uc.constraint_name = cols.constraint_name
WHERE constraint_type != 'C')
START WITH table_name = '&&tableName'
AND column_name = '&&columnName'
CONNECT BY NOCYCLE PRIOR table_name = r_table_name
AND PRIOR column_name = r_column_name;
This has been in the product for years - although it wasn't in the product in 2011.
But, simply click on the Model page.
Make sure you are on at least version 4.0 (released in 2013) to access this feature.
How about something like this:
SELECT c.constraint_name, c.constraint_type, c2.constraint_name, c2.constraint_type, c2.table_name
FROM dba_constraints c JOIN dba_constraints c2 ON (c.r_constraint_name = c2.constraint_name)
WHERE c.table_name = <TABLE_OF_INTEREST>
AND c.constraint_TYPE = 'R';
To add to the above answer for sql developer plugin, using the below xml will help in getting the column associated with the foreign key.
<items>
<item type="editor" node="TableNode" vertical="true">
<title><![CDATA[FK References]]></title>
<query>
<sql>
<![CDATA[select a.owner,
a.constraint_name,
a.table_name,
b.column_name,
a.status
from all_constraints a
join all_cons_columns b ON b.constraint_name = a.constraint_name
where a.constraint_type = 'R'
and exists(
select 1
from all_constraints
where constraint_name=a.r_constraint_name
and constraint_type in ('P', 'U')
and table_name = :OBJECT_NAME
and owner = :OBJECT_OWNER)
order by table_name, constraint_name]]>
</sql>
</query>
</item>
</items>
I like to do this with a straight SQL query, rather than messing about with the SQL Developer application.
Here's how I just did it. Best to read through this and understand what's going on, so you can tweak it to fit your needs...
WITH all_primary_keys AS (
SELECT constraint_name AS pk_name,
table_name
FROM all_constraints
WHERE owner = USER
AND constraint_type = 'P'
)
SELECT ac.table_name || ' table has a foreign key called ' || upper(ac.constraint_name)
|| ' which references the primary key ' || upper(ac.r_constraint_name) || ' on table ' || apk.table_name AS foreign_keys
FROM all_constraints ac
LEFT JOIN all_primary_keys apk
ON ac.r_constraint_name = apk.pk_name
WHERE ac.owner = USER
AND ac.constraint_type = 'R'
AND ac.table_name = nvl(upper(:table_name), ac.table_name)
ORDER BY ac.table_name, ac.constraint_name
;
Only Replace table_name with your primary table name
select *
from all_constraints
where r_constraint_name in (
select constraint_name
from all_constraints
where table_name='table_name'
);
Replace MY_OWNER_NAME and MY_TABLE_NAME below and you are ready to go RECURSIVELY:
DECLARE
FUNCTION list_all_child_tables_and_constraints(asked_table_name in VARCHAR2, parent_table_name in VARCHAR2)
RETURN VARCHAR2 IS
current_path VARCHAR2(100);
BEGIN
FOR item IN
(SELECT fk.TABLE_NAME, constraint_parent.FK FK1, constraint_child.FK FK2
FROM all_constraints fk, all_constraints pk,
(SELECT acc.CONSTRAINT_NAME, LISTAGG(acc.COLUMN_NAME, ', ') WITHIN GROUP (ORDER BY acc.COLUMN_NAME) AS FK
FROM ALL_CONS_COLUMNS acc
WHERE acc.OWNER = 'MY_OWNER_NAME'
GROUP BY acc.CONSTRAINT_NAME) constraint_parent,
(SELECT acc.CONSTRAINT_NAME, LISTAGG(acc.COLUMN_NAME, ', ') WITHIN GROUP (ORDER BY acc.COLUMN_NAME) AS FK
FROM ALL_CONS_COLUMNS acc
WHERE acc.OWNER = 'MY_OWNER_NAME'
GROUP BY acc.CONSTRAINT_NAME) constraint_child
WHERE pk.owner = fk.r_owner
AND pk.constraint_name = fk.r_constraint_name
AND fk.constraint_type = 'R'
AND pk.table_name = asked_table_name
AND constraint_parent.CONSTRAINT_NAME = fk.CONSTRAINT_NAME
AND constraint_child.CONSTRAINT_NAME = fk.R_CONSTRAINT_NAME
AND pk.owner = 'MY_OWNER_NAME'
AND fk.owner = 'MY_OWNER_NAME')
LOOP
current_path := parent_table_name || ' // ' || item.TABLE_NAME;
DBMS_OUTPUT.PUT_LINE(current_path);
DBMS_OUTPUT.PUT_LINE(' [' || item.FK1 || '] [' || item.FK2 || ']');
DBMS_OUTPUT.PUT_LINE('');
current_path := list_all_child_tables_and_constraints(item.TABLE_NAME, current_path);
END LOOP;
RETURN '-----------FINISHED-----------';
EXCEPTION
WHEN OTHERS THEN
RETURN '-----------FINISHED-----------';
END list_all_child_tables_and_constraints;
BEGIN
DBMS_OUTPUT.PUT_LINE(list_all_child_tables_and_constraints('MY_TABLE_NAME', ''));
END;

Disable all table constraints in Oracle

How can I disable all table constrains in Oracle with a single command?
This can be either for a single table, a list of tables, or for all tables.
It is better to avoid writing out temporary spool files. Use a PL/SQL block. You can run this from SQL*Plus or put this thing into a package or procedure. The join to USER_TABLES is there to avoid view constraints.
It's unlikely that you really want to disable all constraints (including NOT NULL, primary keys, etc). You should think about putting constraint_type in the WHERE clause.
BEGIN
FOR c IN
(SELECT c.owner, c.table_name, c.constraint_name
FROM user_constraints c, user_tables t
WHERE c.table_name = t.table_name
AND c.status = 'ENABLED'
AND NOT (t.iot_type IS NOT NULL AND c.constraint_type = 'P')
ORDER BY c.constraint_type DESC)
LOOP
dbms_utility.exec_ddl_statement('alter table "' || c.owner || '"."' || c.table_name || '" disable constraint ' || c.constraint_name);
END LOOP;
END;
/
Enabling the constraints again is a bit tricker - you need to enable primary key constraints before you can reference them in a foreign key constraint. This can be done using an ORDER BY on constraint_type. 'P' = primary key, 'R' = foreign key.
BEGIN
FOR c IN
(SELECT c.owner, c.table_name, c.constraint_name
FROM user_constraints c, user_tables t
WHERE c.table_name = t.table_name
AND c.status = 'DISABLED'
ORDER BY c.constraint_type)
LOOP
dbms_utility.exec_ddl_statement('alter table "' || c.owner || '"."' || c.table_name || '" enable constraint ' || c.constraint_name);
END LOOP;
END;
/
To take in count the dependencies between the constraints:
SET Serveroutput ON
BEGIN
FOR c IN
(SELECT c.owner,c.table_name,c.constraint_name
FROM user_constraints c,user_tables t
WHERE c.table_name=t.table_name
AND c.status='ENABLED'
ORDER BY c.constraint_type DESC,c.last_change DESC
)
LOOP
FOR D IN
(SELECT P.Table_Name Parent_Table,C1.Table_Name Child_Table,C1.Owner,P.Constraint_Name Parent_Constraint,
c1.constraint_name Child_Constraint
FROM user_constraints p
JOIN user_constraints c1 ON(p.constraint_name=c1.r_constraint_name)
WHERE(p.constraint_type='P'
OR p.constraint_type='U')
AND c1.constraint_type='R'
AND p.table_name=UPPER(c.table_name)
)
LOOP
dbms_output.put_line('. Disable the constraint ' || d.Child_Constraint ||' (on table '||d.owner || '.' ||
d.Child_Table || ')') ;
dbms_utility.exec_ddl_statement('alter table ' || d.owner || '.' ||d.Child_Table || ' disable constraint ' ||
d.Child_Constraint) ;
END LOOP;
END LOOP;
END;
/
It's not a single command, but here's how I do it. The following script has been designed to run in SQL*Plus. Note, I've purposely written this to only work within the current schema.
set heading off
spool drop_constraints.out
select
'alter table ' ||
owner || '.' ||
table_name ||
' disable constraint ' || -- or 'drop' if you want to permanently remove
constraint_name || ';'
from
user_constraints;
spool off
set heading on
#drop_constraints.out
To restrict what you drop, filter add a where clause to the select statement:-
filter on constraint_type to drop only particular types of constraints
filter on table_name to do it only for one or a few tables.
To run on more than the current schema, modify the select statement to select from all_constraints rather than user_constraints.
Note - for some reason I can't get the underscore to NOT act like an italicization in the previous paragraph. If someone knows how to fix it, please feel free to edit this answer.
Use following cursor to disable all constraint.. And alter query for enable constraints...
DECLARE
cursor r1 is select * from user_constraints;
cursor r2 is select * from user_tables;
BEGIN
FOR c1 IN r1
loop
for c2 in r2
loop
if c1.table_name = c2.table_name and c1.status = 'ENABLED' THEN
dbms_utility.exec_ddl_statement('alter table ' || c1.owner || '.' || c1.table_name || ' disable constraint ' || c1.constraint_name);
end if;
end loop;
END LOOP;
END;
/
This can be scripted in PL/SQL pretty simply based on the DBA/ALL/USER_CONSTRAINTS system view, but various details make not as trivial as it sounds. You have to be careful about the order in which it is done and you also have to take account of the presence of unique indexes.
The order is important because you cannot drop a unique or primary key that is referenced by a foreign key, and there could be foreign keys on tables in other schemas that reference primary keys in your own, so unless you have ALTER ANY TABLE privilege then you cannot drop those PKs and UKs. Also you cannot switch a unique index to being a non-unique index so you have to drop it in order to drop the constraint (for this reason it's almost always better to implement unique constraints as a "real" constraint that is supported by a non-unique index).
SELECT 'ALTER TABLE '||substr(c.table_name,1,35)||
' DISABLE CONSTRAINT '||constraint_name||' ;'
FROM user_constraints c, user_tables u
WHERE c.table_name = u.table_name;
This statement returns the commands which turn off all the constraints including primary key, foreign keys, and another constraints.
It doesn't look like you can do this with a single command, but here's the closest thing to it that I could find.
This is another way for disabling constraints (it came from https://asktom.oracle.com/pls/asktom/f?p=100:11:2402577774283132::::P11_QUESTION_ID:399218963817)
WITH qry0 AS
(SELECT 'ALTER TABLE '
|| child_tname
|| ' DISABLE CONSTRAINT '
|| child_cons_name
disable_fk
, 'ALTER TABLE '
|| parent_tname
|| ' DISABLE CONSTRAINT '
|| parent.parent_cons_name
disable_pk
FROM (SELECT a.table_name child_tname
,a.constraint_name child_cons_name
,b.r_constraint_name parent_cons_name
,LISTAGG ( column_name, ',') WITHIN GROUP (ORDER BY position) child_columns
FROM user_cons_columns a
,user_constraints b
WHERE a.constraint_name = b.constraint_name AND b.constraint_type = 'R'
GROUP BY a.table_name, a.constraint_name
,b.r_constraint_name) child
,(SELECT a.constraint_name parent_cons_name
,a.table_name parent_tname
,LISTAGG ( column_name, ',') WITHIN GROUP (ORDER BY position) parent_columns
FROM user_cons_columns a
,user_constraints b
WHERE a.constraint_name = b.constraint_name AND b.constraint_type IN ('P', 'U')
GROUP BY a.table_name, a.constraint_name) parent
WHERE child.parent_cons_name = parent.parent_cons_name
AND (parent.parent_tname LIKE 'V2_%' OR child.child_tname LIKE 'V2_%'))
SELECT DISTINCT disable_pk
FROM qry0
UNION
SELECT DISTINCT disable_fk
FROM qry0;
works like a charm
In the "disable" script, the order by clause should be that:
ORDER BY c.constraint_type DESC, c.last_change DESC
The goal of this clause is disable the constraints in the right order.
with cursor for loop (user = 'TRANEE', table = 'D')
declare
constr all_constraints.constraint_name%TYPE;
begin
for constr in
(select constraint_name from all_constraints
where table_name = 'D'
and owner = 'TRANEE')
loop
execute immediate 'alter table D disable constraint '||constr.constraint_name;
end loop;
end;
/
(If you change disable to enable, you can make all constraints enable)
You can execute all the commands returned by the following query :
select 'ALTER TABLE '||substr(c.table_name,1,35)||
' DISABLE CONSTRAINT '||constraint_name||' ;'
from user_constraints c
--where c.table_name = 'TABLE_NAME' ;