Create Unique Index on a table with duplicate rows in Oracle - sql

I have a table which has a UNIQUE INDEX on 6 different columns. However, there are duplicates in the table. When I drop the index and try to re-create it, it throws error saying there are duplicate values.
Is there a way in which I can have the duplicate rows and still create the unique index ?
I see that there are NOVALIDATE options for constraints. Is there anything similar for Indexes.
I am guessing there should be a way since there duplicate rows in the table with a valid UNIQUE INDEX.
Kindly assist.

You can create a UNIQUE index on your table, even if it has duplicates, if you mark the index as UNUSABLE. This means that the index will exist but the system can't make use of it. To do so use a command similar to
CREATE UNIQUE INDEX UNUSABLE_UNIQUE_IDX_SUCCEEDS
ON TABLE_WITH_DUPS(ID)
UNUSABLE
db<>fiddle here
CREATE INDEX docs here

As if you don't want to get error ORA-00001 Unique constraint violated error during multiple insert operations even violation occurs unless the inserted data commited. Then you can make the unique key deferrable initially deferred such as
alter table tab
drop constraint Ukey [cascade];
alter table tab
add constraint Ukey unique ( col1, col2, ..., col6 )
deferrable initially deferred
the above cascade option is related to removing the unique key even if there exist foreign keys in the child tables of the table tab.

Related

Making unique index case-insensitive

I have a unique index on the table and I need to make it case-insensitive, because I started getting duplicates in that table:
TEST
Test
TeSt
To fix the issue I was trying to drop existing index and re-create it:
ALTER TABLE table1 drop constraint test_uk1;
DROP INDEX test_uk1;
CREATE UNIQUE INDEX test_uk1 ON table1(UPPER(column1));
ALTER TABLE table1 ADD CONSTRAINT test_uk1 UNIQUE (column1) USING INDEX test_uk1 ENABLE VALIDATE;
I got an error ORA-14196: Specified index cannot be used to enforce the constraint. on the last statement.
Is there a better way to accomplish this with Oracle?
You can use a virtual column to normalise the case of the string and then put the unique constraint on the virtual column:
CREATE TABLE table_name (
value VARCHAR2(20),
uvalue VARCHAR2(20)
GENERATED ALWAYS AS (UPPER(value))
CONSTRAINT table_name__uvalue__u UNIQUE
);
Then:
INSERT INTO table_name (value) VALUES ('abc');
INSERT INTO table_name (value) VALUES ('aBc');
Inserts one row and the second statement fails with:
ORA-00001: unique constraint (FIDDLE_QDGWKZFBAWPLSRVHJNHN.TABLE_NAME__UVALUE__U) violated
db<>fiddle here
You need not to ALTER TABLE table1 ADD CONSTRAINT ..., the definition of the functional based index is enough for the creation of the unique constraint.
It is also wrong, as you use UNIQUE (column1) which you do not want, so simple skip this statement.
CREATE UNIQUE INDEX test_uk1 ON table1(UPPER(column1));
insert into table1 (column1) values('x');
insert into table1 (column1) values('X');
ORA-00001: unique constraint (XXX.TEST_UK1) violated
Even independently of the DBMS (Oracle, SQL Server, DB2, Vertica, PostgreSQL, you name them), Indexes live and die with the fact that data is not modified/derived before the index or the optimisation taking advantage of the index is applied.
So your approach is doomed, as far as I can tell.
Try this:
ALTER TABLE table1 ADD column1_u DEFAULT UPPER(column1);
CREATE UNIQUE INDEX test_uk1 ON table1(column1_u);
ALTER TABLE table1 ADD CONSTRAINT test_uk1 UNIQUE(column1_u)
USING INDEX test_uk1 ENABLE VALIDATE;
I know, it's a long transaction if your table is big, as you need to shuffle half the tablespace, but it's worth it ..

How to add unique index and delete duplicates

I want to add a unique index in my DB, but some data has already been duplicated.
I am trying out this using a test table before applying to the actual one.
It seems that if there are duplicated rows then we wouldn't be able to add the unique constraint.
I want to add the unique constraint and do not care which row gets deleted.
When I run the following
ALTER TABLE test_user ADD CONSTRAINT test_constraint UNIQUE (personid);
I am getting this error
ERROR: could not create unique index "test_constraint"
DETAIL: Key (personid)=(1) is duplicated.
SQL state: 23505
What would be the best way to achieve this? I am using Postgres as the DB
Create a copy of the table eliminating duplicates:
CREATE TABLE test_user_new (LIKE test_user);
INSERT INTO test_user_new
SELECT DISTINCT ON (id) *
FROM test_user;
ALTER TABLE test_user_new PRIMARY KEY (personid);
Then replace the original table:
DROP TABLE test_user;
ALTER TABLE test_user_new RENAME TO test_user;

What is the difference between a primary key and an index when it comes to inserting records?

I have to insert data into a table that has a PK in it. I also have another table that has a clustered index in it.
Should I drop the PK or the INDEX for the the best INSERT speeds? Then recreate them afterwards?
I load data to these types of tables on a routine basis and I want to make sure I am using the quickest way possible in all situations.
A primary key uniquely identifies a record and has other uses as well. An index makes select queries run faster.
You should never drop your primary key.
Whether or not you drop and re-create indexes when adding records depends on the circumstances.
Primary Key : Uniquely identifies the the data & we cannot insert duplicate Data.
Index : Index help us to get out data to us very quickly.
Very Important Concept about Primary key & Index
Suppose your column is marked with the primary key then Clustered Index automatically gets created,
If no clutstered index is already present in the table
To See that Your Index is Created Successfully, You can use.
sp_helpindex Index_Name
- About Index :
You cannot create a unique index on a single column if that column contains NULL in more than one row. Similarly, you cannot create a unique index on multiple columns if the combination of columns contains NULL in more than one row. These are treated as duplicate values for indexing purposes.
- About Primary Key :
All columns defined within a PRIMARY KEY constraint must be defined as NOT NULL. If nullability is not specified, all columns participating in a PRIMARY KEY constraint have their nullability set to NOT NULL.

Oracle Unique Indexes

I was creating a new table today in 10g when I noticed an interesting behavior. Here is an example of what I did:
CREATE TABLE test_table ( field_1 INTEGER PRIMARY KEY );
Oracle will by default, create a non-null unique index for the primary key. I double checked this. After a quick check, I find a unique index name SYS_C0065645. Everything is working as expected so far. Now I did this:
CREATE TABLE test_table ( field_1 INTEGER,
CONSTRAINT pk_test_table PRIMARY KEY (field_1) USING INDEX (CREATE INDEX idx_test_table_00 ON test_table (field_1)));
After describing my newly created index idx_test_table_00, I see that it is non-unique. I tried to insert duplicate data into the table and was stopped by the primary key constraint, proving that the functionality has not been affected. It seems strange to me that Oracle would allow a non-unique index to be used for a primary key constraint. Why is this allowed?
There is actually no structural difference between a unique index and a non-unique index, Oracle can use either for the PK constraint. One advantage of allowing a PK definition like this is that you can disable or defer the constraint for data loading - this isn't possible with a unique index, so one could argue that this implementation is more flexible.
Why not allow it? I love that Oracle gives you lots of options and flexibility.
Maybe you can create one index and use it for two purposes:
validate the PK
help a query perform better
Oracle will by default create a non-null unique index
Oh, and the index has nothing to do with the not null aspect.
see this excellent article about non-unique indexes policing primary keys by Richard Foote. Richard shows that you will take a performance hit when using a non-unique index.
In other words: don't use non-unique indexes to police a primary key constraint unless you really need the constraint to be deferrable.

Does making a column unique force an index to be created?

In SQL Server 2005+ (I use both), does adding the UNIQUE constraint to a column automatically create an index, or should I still CREATE INDEX?
See this MSDN article:
The Database Engine automatically
creates a UNIQUE index to enforce the
uniqueness requirement of the UNIQUE
constraint.
If you do create an index, you'll end up with two indexes, as this example demonstrates:
create table TestTable (id int)
alter table TestTable add constraint unique_id unique (id)
create unique index ix_TestTable_id on TestTable (id)
select * from sys.indexes where [object_id] = object_id('TestTable')
This will display two unique indexes on TestTable; and the HEAP that represents the table itself.
Yes, it does.
In fact, you can even create a CLUSTERED UNIQUE CONSTRAINT:
ALTER TABLE mytable ADD CONSTRAINT UX_mytable_col1 UNIQUE CLUSTERED (col1)
, which will make the table to be clustered on col1.
Almost all databases create an index for UNIQUE CONSTRAINT, otherwise it would be very hard to maintain it.
Oracle doesn't even distinguish between UNIQUE CONSTRAINT and UNIQUE INDEX: one command is just a synonym for another.
The only difference in Oracle is that a UNIQUE INDEX should have a user-supplied name, while a UNIQUE CONSTRAINT may be created with a system-generated name:
ALTER TABLE mytable MODIFY col1 UNIQUE
This will create an index called SYS_CXXXXXX.
An index is created when you add a unique constraint:
Reference -- see the second paragraph.
When a UNIQUE constraint is added to
an existing column or columns in the
table, by default, the Database Engine
examines the existing data in the
columns to make sure all values are
unique. If a UNIQUE constraint is
added to a column that has duplicated
values, the Database Engine returns an
error and does not add the constraint.
The Database Engine automatically
creates a UNIQUE index to enforce the
uniqueness requirement of the UNIQUE
constraint. Therefore, if an attempt
to insert a duplicate row is made, the
Database Engine returns an error
message that states the UNIQUE
constraint has been violated and does
not add the row to the table. Unless a
clustered index is explicitly
specified, a unique, nonclustered
index is created by default to enforce
the UNIQUE constraint.