I understand I can't do this straightforward from studying similar questions on stackoverflow and other sites.
However, I need to do this and I'm willing to go with workarounds.
I tried to create a non-unique index with online and parallel, and then drop the old unique index. However, it fails saying ORA-01408: such column list already indexed.
How to convert an unique index to a non-unique one?
If you don't want to drop the old index before creating the new one, you can cheat a bit by creating the new index with an additional useless column, e.g.:
Assuming a table with the following configuration:
create table mytable (id number);
create unique index myunique on mytable (id);
To convert the index to non unique:
create index temp on mytable (id, 1);
drop index myunique;
create index mynonunique on mytable (id);
drop index temp;
In practice I'm not sure how necessary this is - generally I'd just drop and recreate the index in some low-activity period, preferably take the application down.
Oracle now supports multiple indexes applied to the same set of columns as long as they differ in uniqueness (and/or in some other properties such as bitmap vs. btree and partitioning) and
as long as only one of them is visible.
Therefore you can alter the existing index - changing it to invisible without dropping it and then create a new non-unique index.
CREATE TABLE mytable (id NUMBER);
CREATE UNIQUE INDEX mytable_unique_idx ON mytable(id);
ALTER INDEX mytable_unique_idx INVISIBLE;
CREATE INDEX mytable_nonunique_idx ON mytable(id);
Note that invisible indexes are still maintained by the database and you can change between them by turning one of them to invisible and the second one to visible.
Related
I am fairly new to the oracle database world so i'm a little confused with the requirement here that I have for one of the bootcamps that I am supposed to complete at the new work place.
First requirement is I need to create an unique constraint UNIQ_BEL_CLIENT_EMP on client_id and client_nbr.
which I did as
CONSTRAINT UNIQ_BEL_CLIENT_EMP UNIQUE(client_id,client_nbr)
Then it also says that the unique constraint will automatically create a unique index behind the scenes so specify PDC_IX for the index tablespace.
I understand we can specify index table space for the given column/ columns which we create explicitly, but how can we specify a index table space for something created behind the scenes? I will be highly obliged if someone could help me answer this question.
OR is it valid to do something like this if the unique index is created behind the scenes for unique constraint????
CONSTRAINT UNIQ_BEL_CLIENT_EMP UNIQUE(client_id, client_nbr) USING INDEX TABLESPACE PDC_IX
You can create the index you want inline with the constraint and specify the tablespace there. E.g.,
CREATE TABLE matt1 ( a number,
CONSTRAINT matt1_u1 UNIQUE (a)
USING INDEX ( CREATE INDEX matt1_u1_idx ON matt1 (a) TABLESPACE USERS ) );
I have a table with Col1 and Col2 as a composite primary key pk_composit_key and a unique index that was automatically created for the constraint.
I then altered the table to add new column Col3.
I dropped the pk_composit_key constraint:
ALTER TABLE table_name DROP CONSTRAINT pk_composit_key;
Now, When I tried to insert records I got ORA-00001: unique constraint pk_composit_key violated.
Why am I getting that error?
When the key was dropped why wasn't the unique index dropped automatically?
You mentioned exporting and importing the schema, and if that happened in the environment that showed this behaviour it would explain what you're seeing; at least if you used legacy imp rather than the data pump impdp.
The original import documentation states the order objects are imported:
Table objects are imported as they are read from the export dump file. The dump file contains objects in the following order:
Type definitions
Table definitions
Table data
Table indexes
Integrity constraints, views, procedures, and triggers
Bitmap, function-based, and domain indexes
So the unique index would have been imported, then the constraint would have been created.
When you drop a primary key constraint:
If the primary key was created using an existing index, then the index is not dropped.
If the primary key was created using a system-generated index, then the index is dropped.
Because of the import order, the constraint is using an existing index,so the first bullet applies; and the index is retained when the constraint is dropped.
You can use the drop index clause to drop the index even if it wasn't created automatically:
ALTER TABLE table_name DROP CONSTRAINT pk_composit_key DROP INDEX;
See also My Oracle Support note 370633.1; and 1455492.1 suggests similar behaviour will occur with data pump import as well. I'm not aware of any way to check if an index is associated with a constraint at this level; there is no difference in the dba_constraints or dba_indexes views when you create the index manually or automatically. Including drop index will make it consistent though.
It depends on how unique index was created...below are the various ways and behaviour
1) first create unique index (on the column for which primary key to be defined) and then add the primary key constraint. In this situation your DDL to add the primary key will utilize the existing unique index. So when you drop the primary key it will not drop the index but only primary key. ==> this is your situation I guess...
2) While creating the table you define the primary key OR when you add the primary key when there was no existing unique index for the column(s) on which primary key to be defined, so system will create a unique index and use it for primary key. So in this case when you drop the primary key the unique index will also get dropped.
I need to update the primary key of a large Index Organized Table (20 million rows) on Oracle 11g.
Is it possible to do this using multiple UPDATE queries? i.e. Many smaller UPDATEs of say 100,000 rows at a time. The problem is that one of these UPDATE batches could temporarily produce a duplicate primary key value (there would be no duplicates after all the UPDATEs have completed.)
So, I guess I'm asking is it somehow possible to temporarily disable the primary key constraint (but which is required for an IOT!) or alter the table temporarily some other way. I can have exclusive and offline access to this table.
The only solution I can see is to create a new table and when complete, drop the original table and rename the new table to the original table name.
Am I missing another possibility?
You can't disable / drop the primary key constraint from an IOT, since it is a unique index by definition.
When I need to change an IOT like this, I either do a CTAS (create table as) for a new plain heap table, do my maintenance, and then CTAS a new IOT.
Something like:
create table t_temp as select * from t_iot;
-- do maintenance
create table t_new_iot as select * from t_temp;
If, however, you need to simply add or join a new field to the existing key, you can do this in one step by creating the new IOT structure, then populating directly from the old IOT with a query.
Unfortunately, this is one of the downsides to IOTs.
I would recommend following method:
Create new IOT table partitioned by system with single partition
with exactly same structure as current one.
Lock current IOT table to prevent any DML.
insert into new table as select from current table changing PK values in select. This step
could be repeated several times if needed. In this case it's better
to do it in another session to keep lock on original table.
Exchange partition of new table with original table.
I have a table Customer_Chronics in Oracle 11g.
The table has three key columns as shown below :
branch_code
customer_id
period
I have partitioned by table by list of branch_code, and now I'm having dilemma. Which is better:
Create unique index indexNumberOne on Customer_Chronics (PERIOD, CUSTOMER_ID);
Create unique index indexNumberTwo on Customer_Chronics (branch_code, PERIOD, CUSTOMER_ID);
The actual data must be unique by period, customer_id. If I put a unique index only on these two columns Oracle will check all partitions on the table when inserting new records?
The only way to enforce uniqueness is with a unique constraint on the columns of interest. So that's your first option. The database will check all values across all partitions it this case. But as it's a unique index that shouldn't take too long no matter how big the table gets (if that's your concern).
Yes, If you put unique index on that two columns only, Oracle will create a global index and will check all partitions. This is one of challenges I face sometime because we prefer local indexs for big tables (small tables should be OK).
I have a few non-unique constraints that I want to alter into unique constraints ( business rules have changed since the data model was made ). Is there any way to do it with out dropping and recreating as a unique constraint? I was thinking there would be an option in the alter constraint command, but I have not found anything.
Thanks!!
You cannot convert a non-unique index into a unique index.
(It's difficult to say what cannot be done. I'm basing this answer on looking at the ALTER INDEX page of the SQL Language Reference, searching for the word UNIQUE, and not finding any relevant hints. I looked at 11g instead of 10g, but that's probably better in this case because there are a few features that exist in 10g but are only documented in 11g.)
However, you can use a non-unique index for a unique constraint. But there are some performance considerations: a unique index would be smaller and faster.
create table my_table(a number);
create index my_table_index on my_table(a);
alter table my_table add constraint my_table_unique unique (a)
using index my_table_index;
You can't modify a constraint in the way you wish you can only drop and recreate it. If you want to do this with no downtime then look into the DBMS_REDEFINITION package.
In my case, just do drop and re-create the index:
DROP INDEX index_name;
CREATE UNIQUE INDEX index_name ON table_name (col01,col02) TABLESPACE indx;