Show SQL constraints in multiple tables - sql

Let say I have these 3 constraint given:
ALTER TABLE actor ADD CONSTRAINT PK_ACTORID PRIMARY KEY (actor_id);
ALTER TABLE film ADD CONSTRAINT PK_FILMID PRIMARY KEY (film_id);
ALTER TABLE film_actor ADD CONSTRAINT FK_FILMID1 FOREIGN KEY (film_id) REFERENCES film;
I need to write sql to show these table constraints:
-- Check which constraints added in ACTOR table
SELECT OWNER, CONSTRAINT_NAME, TABLE_NAME, SEARCH_CONDITION, INDEX_NAME
FROM USER_CONSTRAINTS
WHERE TABLE_NAME = 'ACTOR';
-- Check which constraints added in FILM_ACTOR table
SELECT OWNER, CONSTRAINT_NAME, TABLE_NAME, SEARCH_CONDITION, INDEX_NAME
FROM USER_CONSTRAINTS
WHERE TABLE_NAME = 'FILM_ACTOR';
And the result end up like:
and
My question is, how can I combine two sql statements I wrote as 1 sql and also formatting the result displayed.

Would changing your where statement work?
Something like this:
SELECT OWNER, CONSTRAINT_NAME, TABLE_NAME, SEARCH_CONDITION, INDEX_NAME
FROM USER_CONSTRAINTS
WHERE TABLE_NAME = 'ACTOR' or table_name = 'film' or table_name ='film_actor';

Related

Oracle Oracle hierarchical query to disable foreign keys

I have some code (see below), which uses a hierarchical query that traverses down a table to find all the related Foriegn keys. This seems to be working fine.
Can this be modified not to display the top level table, in this case the TABLE_NAME='PARENT' as I want to wrap this code in PL/SQL in order to create the desired syntax to enable/disable Foriegn keys for all the descendants of a table.
In my example, I have 3 tables. A grandchild table, which REFERENCES a child table and a child table, which REFERENCES the parent table, which is the master table.
The reason for this is to clean up some massive tables and I am trying to figure out the most effective and efficient way to go about this exercise.
We don't have CASCADE DELETE setup as that is too dangerous and some people learned that the hard way unfortunately.
Below is my test case and expected results, which I plan to execute in a procedure.
create table parent (
id NUMBER(10),
value varchar2(30),
constraint parent_pk primary key (id)
);
CREATE TABLE child
( id NUMBER(10) not null,
value NUMBER(10) not null,
constraint child_pk primary key (id,value),
CONSTRAINT parent_child_fk
FOREIGN KEY (id)
REFERENCES parent(id));
CREATE TABLE grandchild
( id NUMBER(10) not null,
value NUMBER(10) not null,
constraint grandchild_pk primary key (id,value),
CONSTRAINT child_grandchild_fk
FOREIGN KEY (id,value)
REFERENCES child(id,value));
insert into parent values (1,'a');
insert into parent values (2,'b');
insert into parent values (3,'c');
insert into child values (1,1);
insert into child values (1,2);
insert into child values (1,3);
insert into child values (2,1);
insert into child values (2,2);
insert into child values (2,3);
insert into child values (3,1);
insert into child values (3,2);
insert into child values (3,3);
insert into grandchild values (1,1);
insert into grandchild values (1,2);
insert into grandchild values (1,3);
insert into grandchild values (2,1);
insert into grandchild values (2,2);
insert into grandchild values (2,3);
insert into grandchild values (3,1);
insert into grandchild values (3,2);
insert into grandchild values (3,3);
In the query I hard code the column name ID.
If possible, I would like to figure it out else I can live with the hard coded value.
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 = 'PARENT' and column_name = 'ID'
connect by nocycle
prior table_name = r_table_name
and prior column_name = r_column_name;
TABLE_NAME
CONSTRAINT_NAME
COLUMN_NAME
R_TABLE_NAME
POSITION
CONSTRAINT_TYPE
PARENT
PARENT_PK
ID
-
1
P
GRANDCHILD
CHILD_GRANDCHILD_FK
ID
CHILD
1
R
CHILD
PARENT_CHILD_FK
ID
PARENT
1
R
Expected results for my test CASE is to generate this syntax:
alter table CHILD disable constraint PARENT_CHILD_FK;
alter table GRANDCHILD disable constraint CHILD_GRANDCHILD_FK;
You can use:
SELECT 'ALTER TABLE "' || u.owner || '"."' || u.table_name || '" '
|| 'DISABLE CONSTRAINT "' || u.constraint_name || '"' AS statement
FROM user_constraints u
INNER JOIN user_constraints r
ON ( u.constraint_type = 'R'
AND r.constraint_type IN ('P', 'U')
AND u.r_owner = r.owner
AND u.r_constraint_name = r.constraint_name)
START WITH r.table_name = 'PARENT'
CONNECT BY PRIOR u.owner = r.owner
AND PRIOR u.table_name = r.table_name;
db<>fiddle here
It is not necessary to use hard code, in fact, it is more troublesome to display the top-level table
with tab1 as (
select t1.CONSTRAINT_NAME,
t1.CONSTRAINT_TYPE,
t1.TABLE_NAME,
t1.R_CONSTRAINT_NAME,
t2.CONSTRAINT_TYPE r_type,
t2.TABLE_NAME r_name
from user_constraints t1,
user_constraints t2
where t1.CONSTRAINT_TYPE = 'R'
and t1.R_CONSTRAINT_NAME = t2.CONSTRAINT_NAME
)
, tab2 as(
select t1.*
from tab1 t1
start with not exists(
select 1 from tab1 v1 where t1.r_name = v1.table_name
)
connect by prior t1.table_name = t1.r_name
)
select 'alter table ' || t1.table_name || ' disable constraint ' || t1.CONSTRAINT_NAME || ';'
from tab2 t1
;

How to remove/Delete the effect of UNIQUE KEY from TABLE

I have UNIQUE KEY attribute on my Table. For my project I deleted that UNIQUE KEY from table , but when try to enter data it still giving the error of UNIQUE KEY VIOLATION.
Already done
to check to commit the database .
to refreshed the entire database.
to find that CONSTRAINT on schema.
SELECT DISTINCT table_name
FROM all_indexes
WHERE index_name = 'CONSTRAINT_NAME';
The above query returns no data (Constraint not found).
I want my data duplicate for one employee without UNIQUE KEY VIOLATION ERROR
Below are some of the queries you can run and check if there is specified index, constraints exist on the table and once you find you can simply drop it. Maybe your unique index was created before the constraint was created:
SELECT * FROM user_cons_columns WHERE table_name = '<your table name>';
select column_name from user_ind_columns where index_name = '<index_name>';
select column_name from user_cons_columns where constraint_name = '<index_name>';
Use below command for dropping index:
DROP INDEX index_name;
Use below command for dropping constraints:
ALTER TABLE <table_name>
DROP CONSTRAINT <constraint_name>
[TL;DR] If you have a UNIQUE INDEX without a UNIQUE CONSTRAINT then you will get the same error message. You need to make sure you have dropped both the index and the constraint.
CREATE TABLE test_data ( id NUMBER );
CREATE UNIQUE INDEX test_data__id__u ON test_data ( id );
ALTER TABLE test_data ADD CONSTRAINT test_data__id__u UNIQUE ( id );
INSERT INTO test_data ( id ) VALUES ( 1 );
INSERT INTO test_data ( id ) VALUES ( 1 );
Will insert one row and will give ORA-00001: unique constraint (FIDDLE_ALGCPMTPWFJZCXIPXNLR.TEST_DATA__ID__U) violated for the second.
If you do:
SELECT * FROM user_constraints WHERE table_name = 'TEST_DATA';
SELECT * FROM user_indexes WHERE table_name = 'TEST_DATA';
Then it will show there is an index and a constraint on the table.
Then if you drop the constraint:
ALTER TABLE test_data DROP CONSTRAINT test_data__id__u;
and try to do:
INSERT INTO test_data ( id ) VALUES ( 1 );
Then you will get:
ORA-00001: unique constraint (FIDDLE_ALGCPMTPWFJZCXIPXNLR.TEST_DATA__ID__U) violated
If you look at the indexes and constraints again:
SELECT * FROM user_constraints WHERE table_name = 'TEST_DATA';
SELECT * FROM user_indexes WHERE table_name = 'TEST_DATA';
Then it will show no constraints but the index is still there. You need to make sure the unique index has been dropped too.
DROP INDEX test_data__id__u;
INSERT INTO test_data ( id ) VALUES ( 1 );
Will then insert the row.
db<>fiddle here

Find only user-defined check constraints in Oracle ALL_CONSTRAINTS

Consider this table definition:
CREATE TABLE foo (
a int not null, -- Implicit not null constraint
b int check (b is not null), -- Explicit not null constraint
c int check (c > 1) -- Explicit constraint
);
I want to discover all the explicit check constraints, i.e. constraints that the user defined in their DDL statement by using the CHECK syntax. Those constraints may or may not be named. In the above example, they're not named. How can I discover only the "explicit" check constraints, ignoring the implicit ones?
E.g. when I query ALL_CONSTRAINTS:
SELECT *
FROM all_constraints
WHERE constraint_type = 'C'
AND table_name = 'FOO';
I don't see any way to distinguish the explicitness/implicitness:
CONSTRAINT_NAME SEARCH_CONDITION GENERATED
---------------------------------------------------
SYS_C00120656 "A" IS NOT NULL GENERATED NAME
SYS_C00120657 b is not null GENERATED NAME
SYS_C00120658 c > 1 GENERATED NAME
I could of course make a heuristic on the unlikelyhood of someone using the exact "COLUMN_NAME" IS NOT NULL syntax (including double quote):
SELECT *
FROM all_constraints
WHERE constraint_type = 'C'
AND table_name = 'FOO'
AND search_condition_vc NOT IN (
SELECT '"' || column_name || '" IS NOT NULL'
FROM all_tab_cols
WHERE table_name = 'FOO'
AND nullable = 'N'
);
This gives me the wanted result:
CONSTRAINT_NAME SEARCH_CONDITION GENERATED
---------------------------------------------------
SYS_C00120657 b is not null GENERATED NAME
SYS_C00120658 c > 1 GENERATED NAME
I'm putting this as an answer here, as this might be good enough for some people, but I'd really like a more reliable solution.
SYS.CDEF$.TYPE# knows the difference between implicit and explicit check constraints. Implicit check constraints are stored as 7, explicit check constraints are stored as 1.
--Explicit constraints only.
select constraint_name, search_condition
from dba_constraints
where (owner, constraint_name) not in
(
--Implicit constraints.
select dba_users.username, sys.con$.name
from sys.cdef$
join sys.con$
on cdef$.con# = con$.con#
join dba_users
on sys.con$.owner# = dba_users.user_id
where cdef$.type# = 7
)
and constraint_type = 'C'
and table_name = 'FOO'
order by 1;
CONSTRAINT_NAME SEARCH_CONDITION
--------------- ----------------
SYS_C00106940 b is not null
SYS_C00106941 c > 1
This solution has the obvious disadvantage of relying on undocumented tables. But it does appear to be more accurate than relying on the text of the condition. Some implicit check constraints are not created with double quotes. I can't reproduce that issue, but I found it happening to the table SYS.TAB$.
Idea: You could compare table with its "shadow" counterpart. CREATE TABLE AS does not preserve user defined check constraints:
-- original table
CREATE TABLE foo (
id int PRIMARY KEY NOT NULL,
a int not null, -- Implicit not null constraint
b int check (b is not null), -- Explicit not null constraint
c int check (c = 1), -- Explicit constraint
d INT CONSTRAINT my_check CHECK (d = 3)
);
-- clone without data(it should be stored in different schema than actual objects)
CREATE TABLE shadow_foo
AS
SELECT *
FROM foo
WHERE 1=2;
-- for Oracle 18c you could consider private temporary tables
CREATE PRIVATE TEMPORARY TABLE ora$shadow_foo ON COMMIT DROP DEFINITION
AS
SELECT * FROM foo WHERE 1=2;
And main query:
SELECT c.*
FROM (SELECT * FROM all_constraints WHERE TABLE_NAME NOT LIKE 'SHADOW%') c
LEFT JOIN (SELECT * FROM all_constraints WHERE TABLE_NAME LIKE 'SHADOW%') c2
ON c2.table_name = 'SHADOW_' || c.table_name
AND c2.owner = c.owner
AND c2.search_condition_vc = c.search_condition_vc
WHERE c2.owner IS NULL
AND c.constraint_type = 'C'
AND c.owner LIKE 'FIDDLE%'
db<>fiddle demo

Change datatype without changing "not null" constraint

I created table "A" with datatype VARCHAR2(3000) with "Not null" constraint. Table "A" has one column "someColumn" which is as primary key. As below:
CREATE TABLE A (
"someColumn" VARCHAR2(3000) NOT NULL
)
ALTER TABLE A
ADD CONSTRAINT pk_A PRIMARY KEY (
"someColumn"
)
Now I want change datatype from VARCHAR2(3000) to VARCHAR2(4000) but I don't want change constraint. So I used:
ALTER TABLE A
MODIFY
(
"someColumn" VARCHAR2(4000)
)
It worked and now I have ddl like below:
PROMPT CREATE TABLE a
CREATE TABLE a (
"someColumn" VARCHAR2(4000) NOT NULL
)
/
PROMPT ALTER TABLE a ADD CONSTRAINT pk_a PRIMARY KEY
ALTER TABLE a
ADD CONSTRAINT pk_a PRIMARY KEY (
"someColumn"
)
/
Then I used code as below:
ALTER TABLE A
MODIFY
(
"someColumn" VARCHAR2(3000) NULL
)
I got message "Alter table, executed..." but when I checked ddl again - I have "Not null" constraint still and new datatype (4000).
It's Oracle error?
To be sure that I don't have any cache in my "SQLTools" I am using:
SELECT * FROM all_tab_cols WHERE table_name = 'A'
Answer:
The change to NULLABLE fails but silently, so I see no error message.
on a column that is primary key you may change the length, but you can't do it nullable (because it is a PK which can't be NULL).
Initial state 3000 length NOT NULL
select COLUMN_NAME, DATA_LENGTH, NULLABLE from user_tab_columns where table_name = 'A';
COLUMN_NAME DATA_LENGTH N
------------------------------ ----------- -
someColumn 3000 N
Change length to 4000 - OK
ALTER TABLE A
MODIFY
(
"someColumn" VARCHAR2(4000)
)
;
select COLUMN_NAME, DATA_LENGTH, NULLABLE from user_tab_columns where table_name = 'A';
COLUMN_NAME DATA_LENGTH N
------------------------------ ----------- -
someColumn 4000 N
Change length to 3000 - OK
make it nullable - fails SILENTLY as PK can't be nullable
ALTER TABLE A
MODIFY
(
"someColumn" VARCHAR2(3000) NULL
);
select COLUMN_NAME, DATA_LENGTH, NULLABLE from user_tab_columns where table_name = 'A';
COLUMN_NAME DATA_LENGTH N
------------------------------ ----------- -
someColumn 3000 N
If you wan't to see a error message - split the change in two (change length and set nullable).
The first one will pass, the second will explicitely fail.
ALTER TABLE A
MODIFY
(
"someColumn" VARCHAR2(3000)
);
ALTER TABLE A
MODIFY
(
"someColumn" NULL
);
ORA-01451: column to be modified to NULL cannot be modified to NULL

ORA-02291:INTEGRITY CONSTRAINT (SYSTEM.SYS_C007150) VIOLATED - PARENT KEY NOT FOUND

When I create the table EMPLOYEE, I made ESSN as a primary key and the SUPERSSN a foreign key from the same table with DNO as a foreign key from the dep table, when I want to insert values that show up and now I am confused.
The table contains the following:
Name Null? Type
----------------------------------------- -------- --------------
ENAME NOT NULL VARCHAR2(30)
ESSN NOT NULL CHAR(14)
BDATE DATE
DNO NUMBER(38)
SUPERSSN CHAR(14)
in first time I used the following command line:
INSERT INTO EMPLOYEE ('JOSEPH','789456','14-DEC-1986','3','123');
then I try without DNO as that:
SQL> INSERT INTO EMPLOYEE (ENAME,ESSN,BDATE)
2 VALUES('JOSEPH','9861050560','14-DEC-1986');
-------------------------------
INSERT INTO EMPLOYEE (ENAME,ESSN,BDATE)
*
ERROR at line 1:
ORA-02291: integrity constraint (SYSTEM.SYS_C007150) violated - parent key not
found
----------------------------
Most likely parent_key record which is SUPERSSN(assuming) must be missing in parent table. You can find that out by
SELECT *
FROM user_constraints
WHERE table_name = 'EMPLOYEE'
So you need to first insert values in parent table of employees table and then insert values in child table.
To find out parent_table do as
SELECT uc.constraint_name
|| CHR (10)
|| '('
|| ucc1.TABLE_NAME
|| '.'
|| ucc1.column_name
|| ')'
constraint_source,
'REFERENCES'
|| CHR (10)
|| '('
|| ucc2.TABLE_NAME
|| '.'
|| ucc2.column_name
|| ')'
references_column
FROM user_constraints uc, user_cons_columns ucc1, user_cons_columns ucc2
WHERE uc.constraint_name = ucc1.constraint_name
AND uc.r_constraint_name = ucc2.constraint_name
AND ucc1.POSITION = ucc2.POSITION
AND UC.TABLE_NAME = 'EMPLOYEE'
AND uc.constraint_type = 'R'
For more details please have a look at this.
And go through this and this as well.
I think the new entry(having foreign key constraint) you are entering is referring to an entry which doesnt exist
Here is a query you could use to check to see if the values in your foreign key table exist or not, and of course if they do not exist then they would have to be inserted to resolve the parent key violation:
SELECT E.* FROM EMPLOYEE E
LEFT JOIN SUPER_TABLE S
ON E.SUPERSSN = S.SUPERSSN
WHERE S.SUPERSSN IS NULL AND E.SUPERSSN IS NOT NULL;
Of course, that is assuming the problem is with the SUPERSSN key. If you have other foreign keys, then you may have to check those as well.