Oracle unique constraint violation referencing a constraint that doesn't seem to exist - oracle

I'm receiving an error that I can't make sense of. The error is pretty straightforward:
ORA-00001: unique constraint (*schema*.*xyz_constraint*) violated
However, what's causing my confusion is the fact that no such constraint seems to exist. It's certainly not defined on the table; the DB in question has almost no referential integrity defined, and the particular table into which I'm inserting data has no key defined.
For what it's worth, I can't find the constraint anywhere in the database:
select *
from all_constraints
where constraint_name like '%xyz_constraint%'
Is there anything I'm overlooking? Thanks.

I had the exact same error and it was not a permissions issue. Rather, the entity turned out to be an INDEX not a CONSTRAINT and I found it with:
SELECT * FROM ALL_INDEXES WHERE INDEX_NAME LIKE '%XYZ_UK1'
...because it did not exist in ALL_CONSTRAINTS or DBA_CONSTRAINTS. Confusing how the error message is the same. I'm running Oracle 11g.

This happens when the constraint belongs to another user and you don't have permissions to it.
Try looking it once again for now from SYS perspective

Schema object names are almost always stored in upper-case. Try
select *
from all_constraints
where constraint_name like '%XYZ_CONSTRAINT%'
ORA-00001 usually happens for duplicate primary keys. Are you sure you don't have one on the table?

Related

Oracle - Why must constraint_name be unique if owned by a different schema?

In Oracle, if you try to explicitly define the schema for a constraint in a CREATE TABLE statement it will result in a ORA-00904: : invalid identifier error:
CREATE TABLE SCHEMA1.MY_TABLE
(
TABLE_ID NUMBER(5)
, FLAG VARCHAR2(1) DEFAULT 'F'
, CONSTRAINT SCHEMA1.MY_TABLE_PK PRIMARY KEY (TABLE_ID) -- Parser doesn't like 'SCHEMA1'
, CONSTRAINT SCHEMA1.MY_TABLE_FLAG_CK CHECK (FLAG IN ('T', 'F')) --Same issue
);
This is no big deal because the constraint OWNER defaults to the same schema as defined in the CREATE TABLE declaration (or at least in the schema you are signed into - my accounts don't have the rights to validate). This can be confirmed by pulling up the constraint in ALL_CONSTRAINTS or DBA_CONSTRAINTS and viewing the OWNER value (which would read SCHEMA1 for the two constraints above).
But if you then follow up this statement with a second duplicate statement under a different schema:
CREATE TABLE SCHEMA2.MY_TABLE
(
TABLE_ID NUMBER(5)
, FLAG VARCHAR2(1) DEFAULT 'F'
, CONSTRAINT MY_TABLE_PK PRIMARY KEY (TABLE_ID) --This constraint already exists
, CONSTRAINT MY_TABLE_FLAG_CK CHECK (FLAG IN ('T', 'F')) --This one too
);
this results in an ORA-00955: name is already used by an existing object error.
My understanding of constraints are that they are just another object on the database which I would have assumed were subject to the same ownership rules with which I'm familiar. But based on the behavior above it is clear that they do not behave like most objects on the database.
Questions
What is it about constraints that requires their names be unique across all schemas (unlike other objects on the database)?
Does anyone know the technical reason for this naming requirement?
For context, I've run into a scenario at work where I had wanted to store duplicate names under different schemas (don't ask... it was inherited duplication and I'm just trying to stay consistent until I have funding to refactor). Now, I realize that I can very simply add the schema to the name and bypass this problem quickly but this rubs my OCD the wrong way so I'd like to better understand just why I can't do what I'm trying to do.
----------------------------- UPDATE ---------------------------
Okay... so I'm a fool. Please note that the above scenario cannot be repeated given a clean environment. After trying to reproduce the issue, I now realize what happened.
I'm currently working on cleaning up some DDL statements in preparation for a production release. I'm not the only developer in this environment and my offshore team has been working on these same tables. I have been editing some preexisting DDL scripts in preparation for a production release and had added some needed constraints to a few CREATE TABLE statements.
It would appear that I had failed to run my DROP scripts before running the second statement in SCHEMA2. My confusion was due to thinking that I was getting the ORA-00955 error because of the new constraints I was adding when in actuality it was because the SCHEMA2.MY_TABLE already existed in this environment. This misdiagnosis was compounded by me changing my constraint names and then rerunning all of my scripts successfully (as I must have run my DROP statements in all schemas before retesting). As a result I thought that I had observed unforeseen behavior when I really had not.
Thank you to everyone who commented for showing me the light!
What's missing in your question is the user under which you run the script. But here's a little experiment.
Connected to the database as user system. I have schemas NGM42 and NGM41 available for the experiment.
CREATE TABLE NGM41.MY_TABLE
(
TABLE_ID NUMBER(5)
, FLAG VARCHAR2(1) DEFAULT 'F'
, CONSTRAINT MY_TABLE_PK PRIMARY KEY (TABLE_ID) -- Parser doesn't like 'SCHEMA1'
, CONSTRAINT MY_TABLE_FLAG_CK CHECK (FLAG IN ('T', 'F')) --Same issue
);
CREATE TABLE NGM42.MY_TABLE
(
TABLE_ID NUMBER(5)
, FLAG VARCHAR2(1) DEFAULT 'F'
, CONSTRAINT MY_TABLE_PK PRIMARY KEY (TABLE_ID)
, CONSTRAINT MY_TABLE_FLAG_CK CHECK (FLAG IN ('T', 'F'))
);
Both statements run succesfully. So what happened to the constraints?
select owner,constraint_name from all_constraints
where constraint_name in ('MY_TABLE_PK','MY_TABLE_FLAG_CK')
NGM42 MY_TABLE_PK
NGM41 MY_TABLE_PK
NGM41 MY_TABLE_FLAG_CK
NGM42 MY_TABLE_FLAG_CK
The constraints are created in the same schema as the table. As you can see they do not need to be globally unique in the database.

Enforcement of unique/primary key - drop index

I am trying to drop an index :
DROP INDEX PK_CHARGES
but I get this error
cannot drop index used for enforcement of unique/primary key
Why I am getting this error? I will provide further information if you need any.
How to solve it?
Edit I have no primary key in the table, but I found this weird index that I don't remember I had added:
index name = SYS_C0040476 which have the same columns
You can query the ALL_CONSTRAINTS performance view to see which constraint the index is used by, and which table it applies to, e.g:
select owner, constraint_name, constraint_type,
table_name, index_owner, index_name
from all_constraints
where index_name = 'PK_CHARGES';
I would expect the table name to be 'CHARGES', the constraint name to match the index name, and the constraint type to be 'P'. But since you have a table in mind, perhaps the names aren't following a helpful convention. Maybe an old version of the table was renamed, which would leave the constraints against the new name (e.g. CHARGES_BACKUP or something).
You said you click on the table, then on the view. Perhaps you're not looking at the table that the constraint/index is on; or perhaps you're looking at a view on top of the actual table. You also mention a SYS_ index on the same columns - which can't be on the same table. Do you have multiple similar tables, or access to multiple schemas? You shold run the above query for that index too. As mentions above, you might find an old version (or versions) of the table.
Once you've identified which table the constraint is on, you'll need to decide whether you should actually be keeping it, and if not you can remove it by dropping the constraint with an ALTER TABLE command.
The problem with
But I found this weird index that I dont rember I hadve add
comes because you didn't add it. You had a primary key, then you dropped it, but when you do that Oracle doesn't drop the associated unique index that every primary key has.
So when you drop a primary key you have to drop the unique index of that primary key, that amazingly has the same name as the primary key had.
So for dropping a MY_TABLE_PK you must do:
ALTER TABLE MY_TABLE DROP PRIMARY KEY DROP INDEX;
so you ensure that the index is dropped as well.
"from pl/sql I right click on the table"
The problem with IDEs is that they make us feel very productive, because we can do things with just a click instead of writing some code. This is a problem because when something unusual happens the IDE is no good for investigation and we lack the understanding of the underlying structure of the database which we need to help ourselves.
If you want to learn the Oracle database the worst thing you can do is download SQL Developer or PLSQL Developer or TOAD. They're all fine tools but the only people who should use them are the people who don't need to use them.
the following worked for me with unique index:
ALTER INDEX UX_CHARGES UNUSABLE
/
DROP INDEX UX_CHARGES
/
see: https://docs.oracle.com/cd/E18283_01/server.112/e17120/indexes004.htm#insertedID3

JDBC Metada retrieve Constraint information

I need information about table and column name from the name of the constraint.
exists someone similar to connection.getMetadata().getX to retrieve the constraint information?
my test case is in Oracle Database, but my best solution I just want to solve with jdbc
If you are talking about foreign key and primary key constraints. The DatabaseMetaData does provide methods for retrieving this information: you can use getImportedKeys(..) and getCrossReference(..) for foreign keys, and getPrimaryKeys(..) and getExportedKeys(..) for primary keys.
Just be careful how you use them: getCrossReference(..) and getExportedKeys are a bit counter-intuitive in my opinion.
If you also need unique constraints, then you should be able to use getIndexInfo(..) with passing true for the parameter unique.
You can get defined constraints information from USER_CONSTRAINTS and ALL_CONSTRAINTS table.
You need to pass required where clause fields.
Example :
select
CONSTRAINT_NAME,
CONSTRAINT_TYPE,
TABLE_NAME,
...
from
USER_CONSTRAINTS
where
CONSTRAINT_NAME like concat(?, '%');

Oracle unique constraint error message

I am maintaining a legacy application and I recently got contacted that people are getting an error message when they try to fill one of our oracle tables. Now, those oracle tables are not in our care, but I still want to try out something to help find the problem.
Anyway, the error message is the following:
java.sql.SQLException: ORA-00001: unique constraint (REO0.PK_TableName) violated :
I know I can find a lot of information online through google and here about this error message. That is not what my question is about.
The question is: the tablename shown here (which I put in bold), is that
the name of the table, or is the
PK_ part added to represent 'primary key' ?
Reason why I ask is: I can't directly get to this database, but somehow I can see all tables in REO0 and I can find one with TableName but not one with *PK_TableName* as the name for a table. So if this PK_ would refer to something like 'primary key' (which the constraint of is violated) then it would make a bit more sense.
PK_tablename is the name of the constraint, and as Alex Poole states in a good comment, it has been specified in the DDL (CREATE TABLE ... (columns, CONSTRAINT PK_tablename PRIMARY KEY(columns...) ), or ALTER TABLE ... ADD CONSTRAINT PK_tablename PRIMARY KEY(columns...) or CREATE UNIQUE INDEX PK_tablename ON ... (columns) for example). When no name has been given, Oracle generates a name which begins with SYS.
Note that usually PK_x suggests a primary key for table x, but your constraint might also be a foreign key constraint or a not null constraint for example.
The following query will tell you all:
SELECT * FROM all_constraints WHERE constraint_name = 'PK_TABLENAME'

How can I drop a "not null" constraint in Oracle when I don't know the name of the constraint?

I have a database which has a NOT NULL constraint on a field, and I want to remove this constraint. The complicating factor is that this constraint has a system-defined name, and that constraint's name differs between the production server, integration server, and the various developer databases. Our current process is to check in change scripts, and an automated task executes the appropriate queries through sqlplus against the target database, so I'd prefer a solution that could just be sent straight into sqlplus.
On my own database, the SQL to drop this would be:
alter table MYTABLE drop constraint SYS_C0044566
I can see the constraint when I query the all_constraints view:
select * from all_constraints where table_name = 'MYTABLE'
but I am not sure how to work with the SEARCH_CONDITION's LONG data type or how best to dynamically delete the looked-up constraint even after I know its name.
So, how can I create a change script that can drop this constraint based on what it is, rather than what its name is?
EDIT:
#Allan's answer is a good one, but I am concerned (in my lack of Oracle expertise) that it may not be universally true that any constraint that might have a system-generated name will have associated with it a way to remove the constraint without having to know its name. Is it true that there will always be a way to avoid having to know a system-named constraint's name when logically dropping that constraint?
alter table MYTABLE modify (MYCOLUMN null);
In Oracle, not null constraints are created automatically when not null is specified for a column. Likewise, they are dropped automatically when the column is changed to allow nulls.
Clarifying the revised question: This solution only applies to constraints created for "not null" columns. If you specify "Primary Key" or a check constraint in the column definition without naming it, you'll end up with a system-generated name for the constraint (and the index, for the primary key). In those cases, you'd need to know the name to drop it. The best advice there is to avoid the scenario by making sure you specify a name for all constraints other than "not null". If you find yourself in the situation where you need to drop one of these constraints generically, you'll probably need to resort to PL/SQL and the data-definition tables.
Try:
alter table <your table> modify <column name> null;
Just remember, if the field you want to make nullable is part of a primary key, you can't.
Primary Keys cannot have null fields.
To discover any constraints used, use the code below:
-- Set the long data type for display purposes to 500000.
SET LONG 500000
-- Define a session scope variable.
VARIABLE output CLOB
-- Query the table definition through the <code>DBMS_METADATA</code> package.
SELECT dbms_metadata.get_ddl('TABLE','[Table Described]') INTO :output FROM dual;
This essentially shows a create statement for how the referenced table is made. By knowing how the table is created, you can see all of the table constraints.
Answer taken from Michael McLaughlin's blog: http://michaelmclaughlin.info/db1/lesson-5-querying-data/lab-5-querying-data/ From his Database Design I class.
I was facing the same problem trying to get around a custom check constraint that I needed to updated to allow different values. Problem is that ALL_CONSTRAINTS does't have a way to tell which column the constraint(s) are applied to. The way I managed to do it is by querying ALL_CONS_COLUMNS instead, then dropping each of the constraints by their name and recreate it.
select constraint_name
from all_cons_columns
where table_name = [TABLE_NAME]
and column_name = [COLUMN_NAME];
Something like that happened to me when I made copies of structures to temporary tables, so I removed the not null.
DECLARE
CURSOR cur_temp_not_null IS
SELECT table_name, constraint_name FROM all_constraints WHERE table_name LIKE 'TEMP_%' AND owner='myUSUARIO';
V_sql VARCHAR2(200);
BEGIN
FOR c_not_null IN cur_temp_not_null
LOOP
v_sql :='ALTER TABLE ' || c_not_null.table_name || ' DROP CONSTRAINT '|| c_not_null.constraint_name;
EXECUTE IMMEDIATE v_sql;
END LOOP;
END;
If constraint on column STATUS was created without a name during creating a table, Oracle will assign a random name for it. Unfortunately, we cannot modify the constraint directly.
Steps involved of dropping unnamed constraint linked to column STATUS
Duplicate STATUS field into a new field STATUS2
Define CHECK constraints on STATUS2
Migrate data from STATUS into STATUS2
Drop STATUS column
Rename STATUS2 to STATUS
ALTER TABLE MY_TABLE ADD STATUS2 NVARCHAR2(10) DEFAULT 'OPEN';
ALTER TABLE MY_TABLE ADD CONSTRAINT MY_TABLE_CHECK_STATUS CHECK (STATUS2 IN ('OPEN', 'CLOSED'));
UPDATE MY_TABLE SET STATUS2 = STATUS;
ALTER TABLE MY_TABLE DROP COLUMN STATUS;
ALTER TABLE MY_TABLE RENAME COLUMN STATUS2 TO STATUS;

Resources