Finding ghost constraint from Oracle DB - sql

I had a constraint in a table
CREATE TABLE "USERSAPPLICATIONS" (
"USERID" NUMBER NOT NULL ,
"APPLICATIONNAME" VARCHAR2 (30) NOT NULL ,
CONSTRAINT "PK_USERSAPPLICATIONS" PRIMARY KEY ("USERID","APPLICATIONNAME")
)
/
Two weeks ago I modified the table, added some columns, deleted the constraint "PK_USERSAPPLICATIONS" and added a surrogate key. I can see in Oracle SQL Developer that the constraint PK_USERSAPPLICATIONS does not exist anymore.
Regardless of that, when I try to add two entries with the same userid/applicationName combination, I get an error
SQL Error: ORA-00001: unique constraint (ACCOUNTMP1.PK_USERSAPPLICATIONS) violated
00001. 00000 - "unique constraint (%s.%s) violated"
*Cause: An UPDATE or INSERT statement attempted to insert a duplicate key.
For Trusted Oracle configured in DBMS MAC mode, you may see
this message if a duplicate entry exists at a different level.
*Action: Either remove the unique restriction or do not insert the key.
When I execute the statement
SELECT *
FROM user_cons_columns
WHERE constraint_name = 'PK_USERSAPPLICATIONS'
I get zero rows. How can that be? Oracle shouldn't have any knowledge of the constraint PK_USERSAPPLICATIONS as it has been deleted already weeks ago, and I cannot see it in the database either.

Do you still have the index which was used by that constraint? Because unless you included the DROP INDEX clause when you dropped the constraint it will still be there. Start with
SELECT *
FROM user_indexes
WHERE index_name = 'PK_USERSAPPLICATIONS'
/
Alternatively,
select index_name
from user_indexes
where table_name = 'USERSAPPLICATIONS'
and uniqueness='UNIQUE'
/
or
select index_name
from user_ind_columns
where table_name = 'USERSAPPLICATIONS'
and column_name in ('USERID' ,'APPLICATIONNAME')
/
edit
Proof of concept
SQL> create table t23 (id number not null, alt_key varchar2(10) not null)
2 /
Table created.
SQL> create unique index t23_idx on t23 (id)
2 /
Index created.
SQL> alter table t23 add constraint t23_pk primary key (id) using index
2 /
Table altered.
SQL> insert into t23 values (1, 'SAM I AM')
2 /
1 row created.
SQL> insert into t23 values (1, 'MR KNOX')
2 /
insert into t23 values (1, 'MR KNOX')
*
ERROR at line 1:
ORA-00001: unique constraint (APC.T23_PK) violated
SQL>
So the constraint works. What happens if we drop it, without the DROP INDEX clause?
SQL> alter table t23 drop constraint t23_pk
2 /
Table altered.
SQL> insert into t23 values (1, 'MR KNOX')
2 /
insert into t23 values (1, 'MR KNOX')
*
ERROR at line 1:
ORA-00001: unique constraint (APC.T23_IDX) violated
SQL>
Note the subtle change in the error message. The second failure references the index name, whereas the original message referenced the constraint. If the index name is the same as the constraint name it would be hard to diagnose this.
If you don't explicitly pre-create the unique index Oracle's default behaviour is to create a non-unique index. Consequently, dropping the constraint without dropping the index does not cause this problem. (Caveat this behaviour is true of 11g. I presume - but cannot be sure - that it is also this way in earlier versions).

Try to check for index for this columns. In some cases index associated with constraint isn't dropped after constraint deletion

Related

ENABLE NOVALIDATE on unique index oracle

In oracle, I want to add this unique constraint to a table with some records that contracted this unique constraint. for adding this unique constraint without validating previous data on the table I added ENABLE NOVALIDATE at the end of the statement but it has an error:
ORA-02158: invalid CREATE INDEX option
Is there any way to add this unique index without validating previous records in Table?
create unique index UK_SAME_THREAD ON T_THREADPARTICIPANT
(case when C_OPPOSITE_USER_ID is not null then C_OPPOSITE_USER_ID else null end,
case when C_OPPOSITE_USER_ID is not null then F_PARTICIPANT else null end,
case when C_OPPOSITE_USER_ID is not null then C_CONTACT_TYPE else null end)
ENABLE NOVALIDATE;
Workaround is to a) create index (non-unique), b) create unique constraint that doesn't validate existing values.
Table that contains duplicate ID values:
SQL> select * From test;
ID
----------
1
1
2
This is what you tried to do:
SQL> create unique index i1 on test (id) enable novalidate;
create unique index i1 on test (id) enable novalidate
*
ERROR at line 1:
ORA-02158: invalid CREATE INDEX option
Let's just alter table and add unique constraint (that won't work either):
SQL> alter table test add constraint uk_id unique (id) enable novalidate;
alter table test add constraint uk_id unique (id) enable novalidate
*
ERROR at line 1:
ORA-02299: cannot validate (SCOTT.UK_ID) - duplicate keys found
So: create index first ...
SQL> create index i1_test_id on test (id);
Index created.
... and alter the table next:
SQL> alter table test add constraint uk_id unique (id) enable novalidate;
Table altered.
SQL>
Does it work?
SQL> insert into test (id) values (2);
insert into test (id) values (2)
*
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.UK_ID) violated
SQL> insert into test (id) values (3);
1 row created.
SQL>
I guess it does.

Check for uniqueness of column in postgres table

I need to ensure that the values in a column from a table are unique as part of a larger process.
I'm aware of the UNIQUE constraint, but I'm wondering if there is a better way to do the check.
I'm running the queries using psycopg2 so adding that tag on the off chance there's something in there that can help with this.
If the column is unique I can add a constraint. If the column is not unique adding the constraint will return an error.
If there is already a constraint of the same name a useful error is returned. in this case would prefer to just check for the existing constraint.
If the column is the primary key, the unique constraint can be added without error but in this case it would be preferable to just recognize that the column must be unique based on the primary key.
Code examples of this below.
DROP TABLE IF EXISTS unique_test;
CREATE TABLE unique_test (
pkey INT PRIMARY KEY,
unique_yes CHAR(1),
unique_no CHAR(1)
);
INSERT INTO unique_test (pkey, unique_yes, unique_no)
VALUES(1, 'a', 'a'),
(2, 'b', 'a');
CREATE UNIQUE INDEX CONCURRENTLY u_test_1 ON unique_test (unique_yes);
ALTER TABLE unique_test
ADD CONSTRAINT unique_target_1
UNIQUE USING INDEX u_test_1;
-- the above runs no problem
-- check what happens when column is not unique
CREATE UNIQUE INDEX CONCURRENTLY u_test_2 ON unique_test (unique_no);
ALTER TABLE unique_test
ADD CONSTRAINT unique_target_2
UNIQUE USING INDEX u_test_2;
-- returns:
-- SQL Error [23505]: ERROR: could not create unique index "u_test_2"
-- Detail: Key (unique_no)=(a) is duplicated.
CREATE UNIQUE INDEX CONCURRENTLY u_test_1 ON unique_test (unique_yes);
ALTER TABLE unique_test
ADD CONSTRAINT unique_target_1
UNIQUE USING INDEX u_test_1;
-- returns
-- SQL Error [42P07]: ERROR: relation "unique_target_1" already exists
-- test what happens if adding constrint to primary key column
CREATE UNIQUE INDEX CONCURRENTLY u_test_pkey ON unique_test (pkey);
ALTER TABLE unique_test
ADD CONSTRAINT unique_target_pkey
UNIQUE USING INDEX u_test_pkey;
-- this runs no problem but is inefficient.
If all you want to do is verify that values are unique, then use a query:
select unique_no, count(*)
from unique_test
group by unique_no
having count(*) > 1;
If it needs to be boolean output:
select not exists (
select unique_no, count(*)
from unique_test
group by unique_no
having count(*) > 1
);
If you just want a flag, you can use:
select count(*) <> count(distinct uniq_no) as duplicate_flag
from unique_test;
DELETE FROM
zoo x
USING zoo y
WHERE
x.animal_id < y.animal_id
AND x.animal = y.animal;
I think this is simpler, https://kb.objectrocket.com/postgresql/delete-duplicate-rows-in-postgresql-762 for reference

Postgres breaking null constraint on a serial column

I have a table that I create independently, the primary key is set with the serial type and a sequence applied to the table, but when I try to insert a value a NULL CONSTRAINT error is thrown and the return looks like null was passed, am I missing something in the INSERT statement?
SQL for table generation:
DROP TABLE IF EXISTS public."Team" CASCADE;
CREATE TABLE public."Team" (
"IdTeam" serial PRIMARY KEY,
name text NOT null,
CONSTRAINT "pKeyTeamUnique" UNIQUE ("IdTeam")
);
ALTER TABLE public."Team" OWNER TO postgres;
DROP SEQUENCE IF EXISTS public."Team_IdTeam_seq" CASCADE;
CREATE SEQUENCE public."Team_IdTeam_seq"
AS integer
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER TABLE public."Team_IdTeam_seq" OWNER TO postgres;
ALTER SEQUENCE public."Team_IdTeam_seq" OWNED BY public."Team"."IdTeam";
SQL for insert :
INSERT INTO public."Team" (name) values ('Manchester Untited');
The returning error:
ERROR: null value in column "IdTeam" violates not-null constraint
DETAIL: Failing row contains (null, Manchester Untited).
SQL state: 23502
I am baffled. Why are you trying to define your own sequence when the column is already defined as serial?
Second, a primary key constraint is already unique. There is no need for a separate unique constraint.
Third, quoting identifiers just makes the code harder to write and to read.
You can just do:
DROP TABLE IF EXISTS public.Team CASCADE;
CREATE TABLE public.Team (
IdTeam serial PRIMARY KEY,
name text NOT null
);
INSERT INTO public.Team (name)
VALUES ('Manchester Untited');
Dropping the sequence causes the default definition for the IdTeam column to be dropped. After recreating the sequence you will have to recreate the default definition.

Is there any difference on a table having PK and having and UNIQUE constraint

In TOAD, I can see my table said doesn't have PK. But there is an unique constraint for the PK candidate.
I try to make the field PK but toad said there is already a constraint for it on the table.
And can't remove the constraint because said someone else depend on it.
So should I leave it like that. Or go the extra mile disable all dependencies remove the unique constraint and create a PK?
Let me try to explain it. As Eric said, unique key constraint will accept (many) nulls for the constrained column.
First, create a table with unique key constraint (the one you have now):
SQL> create table test (id number constraint uk_test unique, --> unique key constraint
2 name varchar2(20));
Table created.
SQL> -- This is the first record - no problem with it
SQL> insert into test (id, name) values (1, 'Little');
1 row created.
SQL> -- Uniqueness violated
SQL> insert into test (id, name) values (1, 'Foot');
insert into test (id, name) values (1, 'Foot')
*
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.UK_TEST) violated
SQL> -- Let's insert some NULL values into the constrained column
SQL> insert into test (id, name) values (null, 'Foot');
1 row created.
SQL> insert into test (id, name) values (null, 'Big');
1 row created.
SQL> -- The result: not too pretty, eh?
SQL> select * From test;
ID NAME
---------- --------------------
1 Little
Foot
Big
A step further: apply a new, NOT NULL constraint to the unique key column, so that it "acts" as if it were a primary key:
SQL> delete from test;
3 rows deleted.
SQL> -- add NOT NULL constraint
SQL> alter table test modify id not null;
Table altered.
SQL> -- The first record is OK
SQL> insert into test (id, name) values (1, 'Little');
1 row created.
SQL> -- Uniqueness violated
SQL> insert into test (id, name) values (1, 'Foot');
insert into test (id, name) values (1, 'Foot')
*
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.UK_TEST) violated
SQL> -- This worked previously, but won't any longer because of the NOT NULL constraint
SQL> insert into test (id, name) values (null, 'Foot');
insert into test (id, name) values (null, 'Foot')
*
ERROR at line 1:
ORA-01400: cannot insert NULL into ("SCOTT"."TEST"."ID")
Finally, to show that now it acts as if it were a primary key constraint:
SQL> delete from test;
1 row deleted.
SQL> -- Let's drop the unique key constraint
SQL> alter table test drop constraint uk_test;
Table altered.
SQL> -- Add the primary key constraint (no duplicates, no nulls)
SQL> alter table test add constraint pk_test primary key (id);
Table altered.
SQL> -- The first record is OK
SQL> insert into test (id, name) values (1, 'Little');
1 row created.
SQL> -- Uniqueness violated
SQL> insert into test (id, name) values (1, 'Foot');
insert into test (id, name) values (1, 'Foot')
*
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.PK_TEST) violated
SQL> -- Not null violated
SQL> insert into test (id, name) values (null, 'Foot');
insert into test (id, name) values (null, 'Foot')
*
ERROR at line 1:
ORA-01400: cannot insert NULL into ("SCOTT"."TEST"."ID")
Basically, now you got the same errors as previously, i.e. primary key = unique key + NOT NULL.
You can't create a primary key if the column is already constrained by the unique key - you already know that.
As you can't drop the unique key constraint (because foreign keys reference it), apply the NOT NULL constraint to that column.
Alternatively,
drop all foreign key constraints
drop unique key
create primary key
recreate foreign key constraints
You can replace the UNIQUE constraint for a PK in three easy steps:
Just create the PK with the same column(s).
Then change all FKs to make them point to the PK constraint instead of the UNIQUE constraint.
Finally, drop the UNIQUE constraint.
Easy.

Can I alter the constraints of one table by using the constraints of another table?

I had to drop a table and remake it using an archive. In the process, I lost the table's constraints--things like the primary key--triggers, indices, and more. I have, however, the same table on a different DB, which has all the appropriate constraints.
I have tried adding the constraints, triggers, and indices manually, but there are just too many.
I was wondering if I could do something like:
alter table t73
modify col_n....col_n+1
using (select constraints from t73#otherdb)
No, that won't work.
What you could do is to use some GUI (like TOAD or SQL Developer), find table t73, have a look at its Script which contains all commands (CREATE TABLE, CREATE INDEX, CREATE CONSTRAINT, ...) and copy/paste the ones you need and execute them in your current database.
That would be quick.
If you want to do it right (you know, pretending you know what you're doing, just like I do), then see DBMS_METADATA.GET_DDL and extract those commands from the database.
The final result should be the same.
this is below example how you can use dbms_metadata.get_ddl oracle package
create table EX_EMPLOYEe ( id number(5) null, name varchar2(100))
/
alter table ex_Employee add constraint PK_EX_EMPLOYEE primary key (id)
/
alter table ex_Employee add constraint FK_EX_EMPLOYEE foreign key (id)
references ex_Employee1 (id)
/
create table EX_EMPLOYEe1 ( id number(5) null, name varchar2(100))
/
alter table ex_Employee1 add constraint PK_EX_EMPLOYEE1 primary key (id)
alter table SYS_PARAM_KEY_LABEL
add constraint FK1_SYS_PARAM_KEY_LABEL foreign key (KEY_GROUP_ID)
references SYS_PARAM_KEY_GROUP (KEY_GROUP_ID);
/
CREATE INDEX IDX_EX_EMPLOYEe on ex_employee(name)
/
Create or replace PROCEDURE P_EX_EMPLOYEe as
begin
select id from ex_employee where rownum=1;
end;
/
CREATE OR REPLACE TRIGGER TRG_EX_EMPLOYEe AFTER DELETE ON EX_EMPLOYEe
FOR EACH ROW
BEGIN
DELETE FROM ex_employee1 WHERE id = :OLD.ID;
END;
/
select to_char( dbms_metadata.get_ddl('CONSTRAINT', c.constraint_name)) from user_constraints c where table_name='EX_EMPLOYEE'
and c.constraint_type='P'
union
select to_char( dbms_metadata.get_ddl('REF_CONSTRAINT', c.constraint_name)) from user_constraints c where table_name='EX_EMPLOYEE'
and c.constraint_type='R'
union
select to_char( dbms_metadata.get_ddl('INDEX', c.index_name)) from user_indexes c where table_name='EX_EMPLOYEE'
union
select to_char( dbms_metadata.get_ddl('PROCEDURE', d.name)) from user_dependencies d where d.referenced_name='EX_EMPLOYEE'
and d.type='PROCEDURE'
union
select to_char( dbms_metadata.get_ddl('TRIGGER', d.name)) from user_dependencies d where d.referenced_name='EX_EMPLOYEE'
and d.type='TRIGGER'