Unique constraint on multiple columns - oracle

I am using an oracle table and have created a unique constraint over four columns. Can these columns within the constraint have NULL in them?

you can have NULLs in your columns unless the columns are specified NOT NULL. You will be able to store only one instance of NULLs however (no two sets of same columns will be allowed unless all columns are NULL) :
SQL> CREATE TABLE t (id1 NUMBER, id2 NUMBER);
Table created
SQL> ALTER TABLE t ADD CONSTRAINT u_t UNIQUE (id1, id2);
Table altered
SQL> INSERT INTO t VALUES (1, NULL);
1 row inserted
SQL> INSERT INTO t VALUES (1, NULL);
INSERT INTO t VALUES (1, NULL)
ORA-00001: unique constraint (VNZ.U_T) violated
SQL> /* you can insert two sets of NULL, NULL however */
SQL> INSERT INTO t VALUES (NULL, NULL);
1 row inserted
SQL> INSERT INTO t VALUES (NULL, NULL);
1 row inserted

Yes, Oracle allows UNIQUE constraints to contain columns with NULL contents, but PRIMARY KEY constraints cannot contain columns containing NULL values. (Edited: was "... nullable columns...", but my example below shows that not to be true. Columns in a PK can be defined as nullable, but cannot contain NULL.)
You cannot have a UNIQUE constraint and a PRIMARY KEY constraint with the same columns.
SQL> create table stest (col1 integer not null, col2 integer null);
Table created.
SQL> alter table stest add constraint stest_uq unique (col1, col2);
Table altered.
SQL> insert into stest values (1, 3);
1 row created.
SQL> insert into stest values (1, null);
1 row created.
SQL> insert into stest values (1, null);
insert into stest values (1, null)
*
ERROR at line 1:
ORA-00001: unique constraint (SUSAN_INT.STEST_UQ) violated
SQL> insert into stest values (2, null);
1 row created.
SQL> commit;
Commit complete.
SQL> select * from stest;
COL1 COL2
---------- ----------
1 3
1
2
SQL> alter table stest add constraint stest_pk PRIMARY KEY (col1, col2);
alter table stest add constraint stest_pk PRIMARY KEY (col1, col2)
*
ERROR at line 1:
ORA-01449: column contains NULL values; cannot alter to NOT NULL
SQL> truncate table stest;
Table truncated.
SQL> alter table stest add constraint stest_pk PRIMARY KEY (col1, col2);
alter table stest add constraint stest_pk PRIMARY KEY (col1, col2)
*
ERROR at line 1:
ORA-02261: such unique or primary key already exists in the table
SQL> alter table stest drop constraint stest_uq;
Table altered.
SQL> alter table stest add constraint stest_pk PRIMARY KEY (col1, col2);
Table altered.

Two nulls are considered not equal in Oracle, so these columns can have nulls in them.

Related

Add a primary key column to an old table

So I have a table with some 50+ rows. And currently this tables doesnot have any primary key/ID column in it. Now if I have to add a primary key column, its not allowing me to because already data are present in the table and there is as such no unique column or combination of columns. Can anyone suggest me how to add a primary column to an existing table with data in it.
(From 12.1) You can add a new auto-incremented surrogate key to a table with either:
alter table t
add ( t_id integer generated by default as identity );
Or
create sequence s;
alter table t
add ( t_id integer default s.nextval );
These set the value for all the existing rows. So may take a while on large tables!
You should also look to add a unique constraint on the business keys too though. To do that, take the steps Marmite Bomber suggests.
In your case when the table due to missing PK definition suffers some duplicated records, you may do a stepwise recovery.
In the first step you disables the creation of the new duplicated rows.
Let's assume your PK candidate columns are col1, col2 such as in the example below:
CREATE TABLE test_pk as
SELECT 'A' col1, 1 col2 FROM dual UNION ALL
SELECT 'A' col1, 2 col2 FROM dual UNION ALL
SELECT 'B' col1, 1 col2 FROM dual UNION ALL
SELECT 'B' col1, 1 col2 FROM dual;
You can not define the PK because of the existing duplications
ALTER table test_pk ADD CONSTRAINT my_pk UNIQUE (col1, col2);
-- ORA-02299: cannot validate (xxx.MY_PK) - duplicate keys found
But you can crete an index on the PK columns and set up a constraint in the state ENABLE NOVALIDATE.
This will tolerate existing duplicates, but reject the new once.
CREATE INDEX my_pk_idx ON test_pk(col1, col2);
ALTER TABLE test_pk
ADD CONSTRAINT my_pk UNIQUE (col1,col2) USING INDEX my_pk_idx
ENABLE NOVALIDATE;
Now you may insert new unique rows ...
INSERT INTO test_pk (col1, col2) VALUES ('A', 3);
-- OK
... but you can't create new duplications:
INSERT INTO test_pk (col1, col2) VALUES ('A', 1);
-- ORA-00001: unique constraint (xxx.MY_PK) violated
Later in the second step you may decide to clenup the table and VALIDATE the constraint, which will make a perfect primary key as expected:
-- cleanup
DELETE FROM TEST_PK
WHERE col1 = 'B' AND col2 = 1 AND rownum = 1;
ALTER TABLE test_pk MODIFY CONSTRAINT my_pk ENABLE VALIDATE;

How to change column identify from sequence to GENERATED ALWAYS with data

as my title, I want to change my identity column by sequence to GENERATED ALWAYS.
For ex, I have a table like this:
CREATE SEQUENCE DPT.Deposit_SEQ
START WITH 1
INCREMENT BY 10
NOCACHE
NOCYCLE;
CREATE TABLE DPT.TEST(
Id NUMBER(10)DEFAULT DPT.Deposit_SEQ.nextval NOT NULL
,Code VARCHAR2(20),
CONSTRAINT PK_TEST PRIMARY KEY (ID)
);
Insert into DPT.TEST (ID, CODE) values (1,'ABC');
COMMIT;
Now, I want to change from sequence to GENERATED ALWAYS like this:
Id NUMBER(10) GENERATED ALWAYS AS IDENTITY START WITH 6
INCREMENT BY 10
NOCACHE
NOCYCLE;
I tried by create one more column and drop old column but failed. How can I do that?
Thanks!
"But failed" is not an Oracle error and is difficult to debug.
Anyway, it works for me:
Create table and a sequence, insert some rows:
SQL> CREATE SEQUENCE Deposit_SEQ START WITH 1 INCREMENT BY 10 NOCACHE NOCYCLE;
Sequence created.
SQL> CREATE TABLE TEST
2 (
3 Id NUMBER (10) DEFAULT Deposit_SEQ.NEXTVAL NOT NULL,
4 Code VARCHAR2 (20),
5 CONSTRAINT PK_TEST PRIMARY KEY (ID)
6 );
Table created.
SQL>
SQL> INSERT INTO TEST (ID, CODE)
2 VALUES (1, 'ABC');
1 row created.
SQL> INSERT INTO TEST (ID, CODE)
2 VALUES (3, 'DEF');
1 row created.
SQL> SELECT * FROM test;
ID CODE
---------- --------------------
1 ABC
3 DEF
Drop current primary key column (ID) and add a new, identity column:
SQL> ALTER TABLE test
2 DROP COLUMN id;
Table altered.
SQL> ALTER TABLE test
2 ADD id NUMBER GENERATED ALWAYS AS IDENTITY START WITH 6;
Table altered.
SQL> SELECT * FROM test;
CODE ID
-------------------- ----------
ABC 6
DEF 7
SQL> ALTER TABLE test ADD CONSTRAINT pk_test PRIMARY KEY (id);
Table altered.
SQL>
As you can see, no problem.

cannot insert data into the 4th table

I used the following script to create 4 test tables: dept1, dept2, dept3, and dept4. The code is exactly the same for each table. All tables are created successfully but the insert into statements only worked for the first three tables. After dropping all tables and purge the recyclebin, I moved Create Table dept4 and the following insert into statements to the top of the code. Then the insert into statement does not work for Dept3. Basically, I can only insert data into the first three tables in the script and not able to insert data into the 4th table on the script.
The error message is the following:
SQL Error: ORA-00604: error occurred at recursive SQL level 1
ORA-30667: cannot drop NOT NULL constraint on a DEFAULT ON NULL column
00604. 00000 - "error occurred at recursive SQL level %s"
This happened after some users created identity columns in Oracle 12.1 database. Some users used:
GENERATED ALWAYS AS IDENTITY
Other users used:
GENERATED BY DEFAULT ON NULL AS IDENTITY
Code used:
CREATE TABLE DEPT1 (
DEPT1NO NUMBER(2) NOT NULL,
DNAME VARCHAR2(14),
LOC VARCHAR2(13),
CONSTRAINT DEPT1_PRIMARY_KEY PRIMARY KEY (DEPT1NO));
INSERT INTO DEPT1 VALUES (10,'ACCOUNTING','NEW YORK');
INSERT INTO DEPT1 VALUES (20,'RESEARCH','DALLAS');
INSERT INTO DEPT1 VALUES (30,'SALES','CHICAGO');
INSERT INTO DEPT1 VALUES (40,'OPERATIONS','BOSTON');
CREATE TABLE DEPT2 (
DEPT2NO NUMBER(2) NOT NULL,
DNAME VARCHAR2(14),
LOC VARCHAR2(13),
CONSTRAINT DEPT2_PRIMARY_KEY PRIMARY KEY (DEPT2NO));
INSERT INTO DEPT2 VALUES (10,'ACCOUNTING','NEW YORK');
INSERT INTO DEPT2 VALUES (20,'RESEARCH','DALLAS');
INSERT INTO DEPT2 VALUES (30,'SALES','CHICAGO');
INSERT INTO DEPT2 VALUES (40,'OPERATIONS','BOSTON');
CREATE TABLE DEPT3 (
DEPT3NO NUMBER(2) NOT NULL,
DNAME VARCHAR2(14),
LOC VARCHAR2(13),
CONSTRAINT DEPT3_PRIMARY_KEY PRIMARY KEY (DEPT3NO));
INSERT INTO DEPT3 VALUES (10,'ACCOUNTING','NEW YORK');
INSERT INTO DEPT3 VALUES (20,'RESEARCH','DALLAS');
INSERT INTO DEPT3 VALUES (30,'SALES','CHICAGO');
INSERT INTO DEPT3 VALUES (40,'OPERATIONS','BOSTON');
CREATE TABLE DEPT4 (
DEPT4NO NUMBER(2) NOT NULL,
DNAME VARCHAR2(14),
LOC VARCHAR2(13),
CONSTRAINT DEPT4_PRIMARY_KEY PRIMARY KEY (DEPT4NO));
INSERT INTO DEPT4 VALUES (10,'ACCOUNTING','NEW YORK');
INSERT INTO DEPT4 VALUES (20,'RESEARCH','DALLAS');
INSERT INTO DEPT4 VALUES (30,'SALES','CHICAGO');
INSERT INTO DEPT4 VALUES (40,'OPERATIONS','BOSTON');

parent keys not found Oracle 10g

I have two tables :
SQL> desc SEGMENT
Name Null? Type
----------------------------------------- -------- ----------------------------
INDIP NOT NULL VARCHAR2(11)
NOMSEGMENT NOT NULL VARCHAR2(20)
ETAGE
SQL> desc POSTE
Name Null? Type
----------------------------------------- -------- ----------------------------
NPOSTE NOT NULL VARCHAR2(7)
NOMPOSTE NOT NULL VARCHAR2(20)
INDIP VARCHAR2(11)
AD VARCHAR2(3)
TYPEPOSTE VARCHAR2(9)
NSALLE VARCHAR2(7)
I want to add a constraint as the following :
ALTER TABLE "POSTE" ADD CONSTRAINT "FK_POSTE_SEGMENT" FOREIGN KEY ("INDIP") REFERENCES "SEGMENT" ("INDIP") ENABLE;
But I got this error message :
ERROR at line 1: ORA-02298: cannot validate (AIMAD.FK_POSTE_SEGMENT) -
parent keys not found
How can I solve this
You should check what POSTE table does not contain values in INDIP column what don't exist in INDIP column of SEGMENT table.
Like
SQL> create table t (x int primary key);
SQL> insert into t values(1);
SQL> create table t_c (x int);
SQL> insert into t_c values(1);
SQL> insert into t_c values(2);
SQL> commit;
SQL> alter table t_c add constraint t_c_x foreign key(x)
2 references t(x);
alter table t_c add constraint t_c_x foreign key(x)
*
ORA-02298: cannot validate (SCOTT.T_C_X) - parent key not found
SQL> select * from t_c where not exists (select *
2 from t where t.x = t_c.x);
X
-----------------------
2
Also Oracle provides the ability to create constraint in NOVALIDATE status, this prevents Oracle from checking data during contraint creation:
SQL> alter table t_c add constraint t_c_x foreign key(x)
2 references t(x) enable novalidate;
Table altered.
but this can have undesirable side effects because data in both tables are not consistent.

Copy or show the primary key value into another table as foreign key APEX

I have two tables A and B .i want to copy or show the primary key column value from table A in the foreign key column in table B respectively .is there any method kindly help me.
Regards,
You can populate your primary key value while populating table B or by using a trigger when you are populating table A.
CREATE TABLE t1 (id1 NUMBER, dt DATE);
ALTER TABLE t1 ADD (
CONSTRAINT t1_pk
PRIMARY KEY
(id1));
CREATE TABLE t2 (id2 NUMBER, id1 NUMBER, dt2 DATE);
ALTER TABLE t2 ADD (
CONSTRAINT t2_pk
PRIMARY KEY
(id2));
ALTER TABLE t2
ADD CONSTRAINT t2_r01
FOREIGN KEY (id2)
REFERENCES t1 (id1);
First Approach, by this way you could populate second table when you are inserting values.
INSERT INTO t1
VALUES (1, SYSDATE
);
INSERT INTO t2
VALUES (1, 1, SYSDATE
);
With trigger, so when values are inserted into first table second tables values are populated using a trigger. So primary key value of first table is being inserted into foreign key of table 2.
CREATE OR REPLACE TRIGGER my_trigger
AFTER INSERT
ON t1
FOR EACH ROW
BEGIN
INSERT INTO t2
VALUES (1, :new.id1, SYSDATE
);
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line (TO_CHAR (SQLERRM (-20299)));
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (TO_CHAR (SQLERRM (-20298)));
END;

Resources