How to see contents of Check Constraint on Oracle - oracle

I did not create the database I'm working with, but I would like to see the details of a check constraint.
I know a check constraint on a column is enforcing a set of specific values, and I'd like to know what those values are. For example, if a check constraint is enforcing the character 'Y' and 'N', I want to be able to query the database and see that the accepted values are 'Y' and 'N.'
Is this possible to do through a query?

select constraint_name,search_condition
from all_constraints
where table_name='NAME_OF_YOUR_TABLE'
and constraint_type='C';
Will list the check and the constraint name of all check constraints on a specific table.

Don't forget that the columns in the all_constraints table are case-sensitive. If your select statement returns nothing, that may be why.
(If I had enough rep to comment, on DBA's answer, this would go there.)

Related

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(?, '%');

Use DD view all_constraints to check if a FK constraint would work

My professor whom is teaching a database course asked the following question - currently I have no idea where to start as this seems like an unusual question to ask.
I understand what foreign keys are and how they work, however I am not sure how to answer the below question:
ho and hi are public synonyms for two tables owned by the BLURP schema. Execute one query (even if nested, it can be considered as "one" query) on DD view all_constraints, and discuss whether or not table hi currently satisfies an FK constraint on column hi.olord.
Each column has identical value type CHAR(6) & NOT NULL constraint.
Any help would be appreciated.
First, read the documentation about the all_constraints view.
My guess . . . You professor wants you to query the all_constraints view, and
determine whether there's a referential integrity constraint
from hi.olord
to some column in ho
And, in addition, he expects you to comment on the values you find in other relevant columns. I'd expect you to comment on STATUS and VALIDATED, among others.
If you worked for me, and I were testing you on this, I'd expect you to be able to justify why you included some columns in your query, and why you left others out. You might omit SEARCH_CONDITION, for example, because it applies to CHECK constraints, not to referential integrity constraints. You might include STATUS, because the issue of whether a particular constraint is enabled or disabled is relevant to determining whether "table hi currently satisfies an FK constraint on column hi.olord".

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;

How to constrain a database table so only one row can have a particular value in a column?

Using Oracle, if a column value can be 'YES' or 'NO' is it possible to constrain a table so that only one row can have a 'YES' value?
I would rather redesign the table structure but this is not possible.
[UDPATE] Sadly, null values are not allowed in this table.
Use a function-based index:
create unique index only_one_yes on mytable
(case when col='YES' then 'YES' end);
Oracle only indexes keys that are not completely null, and the CASE expression here ensures that all the 'NO' values are changed to nulls and so not indexed.
This is a kludgy hack, but if the column allows NULLs, then you could use NULL in place of "NO" and use "YES" just as before. Apply a unique key constraint to that column, and you'll never get two "YES" values, but still have many NOs.
Update: #Nick Pierpoint: suggested adding a check constraint so that the column values are restricted to just "YES" and NULL. The syntax is all worked out in his answer.
You will want to check a Tom Kyte article with exactly this question being asked and his answer:
http://tkyte.blogspot.com/2008/05/another-of-day.html
Summary: don't use triggers, don't use autonomous transactions, use two tables.
If you use an Oracle database, then you MUST get to know AskTom and get his books.
It doesn't work on the table definition.
However, if you update the table using a trigger calling a stored procedure, you could make sure that only one row contains "YES".
Set all rows to "NO"
Set the row you want to YES
Following on from my comment to a previous answer by yukondude, I'd add a unique index and a check constraint:
create table mytest (
yesorno varchar2(3 char)
);
create unique index uk_mytest_yesorno on mytest(yesorno);
alter table mytest add constraint ck_mytest_yesorno check (yesorno is null or yesorno = 'YES');
Does Oracle support something like filtered indices (last week I heard that e.g. MSSQL2008 does)? Maybe you can define a unique key which applies only to rows with the value "Yes" in your column.
I guess I'd use a second table to point to the appropriate row in your current table. That other table could be used to store values of other variables too too.

Resources