How work PK in oracle - oracle

I got a task to review and change a PK field in a oracle table (I'm Postgresql and Sql Server guy) I check on TOAD constraints and found this:
PK_POI Primary Key Disabled Not Deferrable Immediate Not Validated 1 MI_PRINX
SYS_C0010910 Check Disabled Not Deferrable Immediate Not Validated 1 "MI_PRINX" IS NOT NULL
For what I can see two constraint where created, but by my understanding a PK is already a NOT NULL field so why need two constraint?
Also I notice both constraint said are Disable but in my test I can insert null values but not the same id twice
So not sure if Disable constraint mean what I thought should mean.

Disable means what you think it means.
Regarding NOT NULL and PRIMARY KEY, they are two constraints. A primary key implies NOT NULL, but if you drop the primary key constraint, the check constraint is still there. See here for details.
Regarding "I can insert null values...": this is because both constraints are disabled.
Regarding "...but not the same id twice": a primary key constraint and the unique index that is used to enforce it are two different things. Can you check if there is an unique index on this column?

Related

Could you tell me some advise Oracle Error?

Sorry, I don't well English.
CREATE TABLE Reservation(
tno NUMBER,
sno NUMBER,
cno NUMBER,
seat_no NUMBER,
Res_Date DATE,
CONSTRAINT FK_RES_TNO FOREIGN KEY (tno) REFERENCES Theater(tno),
CONSTRAINT FK_RES_SNO FOREIGN KEY (sno) REFERENCES Screen(sno),
CONSTRAINT FK_RES_CNO FOREIGN KEY (cno) REFERENCES T_Customer(cno),
CONSTRAINT PK_RESERVATION PRIMARY KEY (tno,sno,cno)
--CONSTRAINT RES_UNIQUE UNIQUE (cno)
);
I Write Oracle Table.
But throw me Error "ORA-02270"
I don't know come to me this message.
Could you tell me some advise?
There would be multiple reasons for having this error,
You may have same primary key already, which might be disabled
Composite primary key in the table may not provide you the unique (this error many happen only when the table is ALTERED, since its new table, this logical check can be ignored)

Do I need a primary key with an Oracle identity column?

I am using Oracle 12c and I have an IDENTITY column set as GENERATED ALWAYS.
CREATE TABLE Customers
(
id NUMBER GENERATED ALWAYS AS IDENTITY,
customerName VARCHAR2(30) NULL,
CONSTRAINT "CUSTOMER_ID_PK" PRIMARY KEY ("ID")
);
Since the ID is automatically from a sequence it will be always unique.
Do I need a PK on the ID column, and if yes, will it impact the performance?
Would an index produce the same result with a better performance on INSERT?
No, you don't need a primary key necessarily, but you should always provide the optimiser as much information about your data as possible - including a unique constraint whenever possible.
In the case of a surrogate key (like your ID), it's almost always appropriate to declare it as a Primary Key, since it's the most likely candidate for referential constraints.
You could use an ordinary index on ID, and performance of lookups will be comparable depending on data volume - but there is virtually no good reason in this case to use a non-unique index instead of a unique index - and there is no good reason in this case to avoid the constraint which will require an index anyway.
Yes, you always should have a Uniqueness constraint (with rare exceptions) on an ID column if indeed it is (and should be) unique, regardless of the method by which it is populated - whether the value is provided by your application code or via an IDENTITY column.

ORA-00955 "name is already used by an existing object"

I need to modify an existing PK. Therefore I drop an recreate it.
ALTER TABLE B DROP CONSTRAINT PK_B;
ALTER TABLE B ADD CONSTRAINT PK_B PRIMARY KEY ("TYP", "NR", "HH", "QUART");
Unfortunately the last Statement will give me an error ORA-00955
If I create the PK constraint like it was defined originally with:
ALTER TABLE B ADD CONSTRAINT PK_B PRIMARY KEY ("TYP", "NR", "HH");
everything works fine.
Perhaps there is an INDEX associated with the PRIMARY KEY CONSTRAINT, and it is also named as PK_B.
You can check it as :
SELECT * FROM USER_INDEXES WHERE TABLE_NAME='<table_name>';
If that's true, then do :
ALTER INDEX "PK_B" RENAME TO "PK_XYZ";
Update : Regarding ALTER INDEX statement, few important points as mentioned by Justin in the comments
Oracle implicitly creates an UNIQUE index to support the PRIMARY KEY CONSTRAINT. Since, the index is of the same name that of the primary key, and now that the primary key is being modified, it is better to drop and re-create the index again as per the definition of the old primary key.
My conclusion :
The primary key constraint is enforced through a unique index.
If Oracle already finds an index – unique or non-unique – it uses it
for the primary key.
If the index was initially created as non-unique, it will continue to
show as non-unique, however it will actually be a unique index.
A good demonstration and quite detailed on other aspects too, by Arup : Primary Keys Guarantee Uniqueness? Think Again.
I had the same issue where I had to do the following to delete reference to a table from the view whilst recreating the database from the scratch. I was searching for the same in tables and indexes first.
connect sys/oracle as sysdba;
select * from all_tables
select * from all_indexes
(finally located the reference in the views)
select * from all_views where view_name like '%WKSTSTATE%';
drop view RUEGEN.WKSTSTATE;

Oracle Database with very few foreign key constraints

I've just started a new project and I am confronted with a production application Oracle 10g database that has just 3 foreign key constraints. I am not used to seeing databases with no foreign key constraints. I am guessing that there may be some performance/concurrency considerations to not using FKs. The reason is that in the logical database schema the architect has specified all the relationships, but these relationships are not implemented in the database as Foreign Key constraints.
Question: I read that I can define a Foreign Key Constraint with RELY NOVALIDATE that will not impact performance. Is it worth while to define RELY FK constraints on this database just so that the relationship can be easily seen? this application is not built using ORM, is it really worth while to do without foreign keys?
The database is denormalised with example below
Table 1 : FINProduct(ID (number), Description(varchar(5)), FINproductCode(varchar(10))...)
Table 2: FINProductCode(ID (number, FINproductCode(varchar(10)) , LastUpdated(datetime)...)
So instead of having a relationship between Tables 1 and 2 the FINproductCode column is just replicated in table 1.
It's too early to drink but I think i need one!
I would be very wary about assuming that the absence of foreign key constraints was a reasoned response to performance issues. There is an overhead to enforcing a foreign key constraint (particularly where appropriate indexes are missing) but it is incredibly unlikely that your application can validate the constraint more efficiently than Oracle can. So the question really is whether you want the small overhead of foreign key constraints or the near certainty that you will get invalid data inserted into the database. It would be extremely unlikely that this is a trade-off that you want to make-- I've yet to meet a business user that would be happy to capture incorrect and incomprehensible data even if doing so was a bit faster than capturing correct data.
Unless there is substantially more background, I would tend to create all the missing foreign key constraints. Creating RELY NOVALIDATE constraints is possible but it defeats the major benefit of foreign key constraints-- preventing invalid data from entering the database in the first place.
It depends on whether you want to add the FK only for documentation purposes or whether you want to prevent future INSERTs/UPDATEs with an invalid FK value.
If you want it only for documentation purposes, I'd create the FK constraint with RELY NOVALIDATE and DISABLE it afterwards - otherwise, Oracle will check it for future INSERTs / UPDATEs.
However: DON'T DO THIS UNLESS YOU ABSOLUTELY NEED IT!
I agree with Justin Cave: In most cases, you should just add "plain" FK constraints - this way, you can ensure that your existing data is correct.
I would try to create the constraints and report violations into a exception table. Fix the data and enable the constraint.
Create some test data
create table parent (pk integer
,data varchar2(1)
,CONSTRAINT PARENT_PK PRIMARY KEY (PK) ENABLE );
create table child (pk integer
,pk_parent integer
,data varchar2(1)
,CONSTRAINT CHILD_PK PRIMARY KEY (PK) ENABLE );
insert into parent values (1,'a');
insert into parent values (2,'b');
insert into child values (1,1,'a');
insert into child values (2,2,'b');
insert into child values (3,3,'c');
Create a foreign key constraint:
alter table child add constraint fk_parent foreign key(pk_parent) references parent(pk);
SQL Error: ORA-02298: Kan (ROB.FK_PARENT) niet valideren - bovenliggende sleutels zijn niet gevonden.
02298. 00000 - "cannot validate (%s.%s) - parent keys not found"
*Cause: an alter table validating constraint failed because the table has
child records.
*Action: Obvious
Create the foreign key with 'enable novalidate' option
alter table child add constraint fk_parent foreign key(pk_parent) references parent(pk) enable novalidate;
table CHILD altered.
insert into child values (4,4,'c');
SQL Error: ORA-02291: Integriteitsbeperking (ROB.FK_PARENT) is geschonden - bovenliggende sleutel is niet gevonden.
02291. 00000 - "integrity constraint (%s.%s) violated - parent key not found"
*Cause: A foreign key value has no matching primary key value.
*Action: Delete the foreign key or add a matching primary key.
No new data violating the FK can be inserted.
Now let's fix the data already in the table that violates the FK constraint
Create an exceptions table and try to enable the constraint:
create table exceptions(row_id rowid,
owner varchar2(30),
table_name varchar2(30),
constraint varchar2(30));
ALTER TABLE child ENABLE constraint fk_parent EXCEPTIONS INTO EXCEPTIONS;
Error report:
SQL Error: ORA-02298: Kan (ROB.FK_PARENT) niet valideren - bovenliggende sleutels zijn niet gevonden.
02298. 00000 - "cannot validate (%s.%s) - parent keys not found"
*Cause: an alter table validating constraint failed because the table has
child records.
*Action: Obvious
Check the exceptions table for problems:
select * from exceptions;
ROW_ID OWNER TABLE_NAME CONSTRAINT
------ ------------------------------ ------------------------------ ------------------------------
AABA78 ROB CHILD FK_PARENT
AAFAAA
Ow9AAC
select * from child where rowid = 'AABA78AAFAAAOw9AAC';
Fix the problem
delete from child where pk = 3;
1 rows deleted.
ALTER TABLE child ENABLE constraint fk_parent EXCEPTIONS INTO EXCEPTIONS;
table CHILD altered.
Constraint enabled and data correct

Create constraint in alter table without checking existing data

I'm trying to create a constraint on the OE.PRODUCT_INFORMATION table which is delivered with Oracle 11g R2.
The constraint should make the PRODUCT_NAME unique.
I've tried it with the following statement:
ALTER TABLE PRODUCT_INFORMATION
ADD CONSTRAINT PRINF_NAME_UNIQUE UNIQUE (PRODUCT_NAME);
The problem is, that in the OE.PRODUCT_INFORMATION there are already product names which currently exist more than twice.
Executing the code above throws the following error:
an alter table validating constraint failed because the table has
duplicate key values.
Is there a possibility that a new created constraint won't be used on existing table data?
I've already tried the DISABLED keyword. But when I enable the constraint then I receive the same error message.
You can certainly create a constraint which will validate any newly inserted or updated records, but which will not be validated against old existing data, using the NOVALIDATE keyword, e.g.:
ALTER TABLE PRODUCT_INFORMATION
ADD CONSTRAINT PRINF_NAME_UNIQUE UNIQUE (PRODUCT_NAME)
NOVALIDATE;
If there is no index on the column, this command will create a non-unique index on the column.
If you are looking to enforce some sort of uniqueness for all future entries whilst keeping your current duplicates you cannot use a UNIQUE constraint.
You could use a trigger on the table to check the value to be inserted against the current table values and if it already exists, prevent the insert.
http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14251/adfns_triggers.htm
or you could just remove the duplicate values and then enfoce your UNIQUE constraint.
EDIT: After Jonearles and Jeffrey Kemp's comments, I'll add that you can actually enable a unique constraint on a table with duplicate values present using the NOVALIDATE clause but you'd not be able to have a unique index on that constrained column.
See Tom Kyte's explanation here.
However, I would still worry about how obvious the intent was to future people who have to support the database. From a support perspective, it'd be more obvious to either remove the duplicates or use the trigger to make your intent clear.
YMMV
You can use deferrable .
ALTER TABLE PRODUCT_INFORMATION
ADD CONSTRAINT PRINF_NAME_UNIQUE UNIQUE (PRODUCT_NAME)
deferrable initially deferred NOVALIDATE;

Resources