Oracle: ORA-01408: such column list already indexed - oracle

I have created a table:
CREATE TABLE SCHEMA_NAME.TABLE_NAME
(
ID VARCHAR2(100) PRIMARY KEY NOT NULL,
A_ID VARCHAR2(100) NOT NULL,
B_ID VARCHAR2(100),
C_ID INTEGER,
CONSTRAINT FK_C_NOTE FOREIGN KEY (C_ID) REFERENCES C(ID),
CONSTRAINT FK_A_NOTE FOREIGN KEY (A_ID) REFERENCES A(ID),
CONSTRAINT FK_B_NOTE FOREIGN KEY (B_ID) REFERENCES B(ID)
);
And I have tried to apply the following indexes:
CREATE INDEX IDX_FK_A_TABLE_NAME on SCHEMA_NAME.TABLE_NAME(A_ID) tablespace TS_SCHEMA_NAME_DATA;
CREATE INDEX IDX_FK_C_TABLE_NAME on SCHEMA_NAME.TABLE_NAME(C_ID) tablespace TS_SCHEMA_NAME_DATA; --Fails
CREATE INDEX IDX_FK_B_TABLE_NAME on SCHEMA_NAME.TABLE_NAME (B_ID) tablespace TS_SCHEMA_NAME_DATA; --Fails
But when I try to create the last two indexes I get:
ORA-01408: such column list already indexed
Why is this? Are these indexes created automatically?
If I try:
SELECT INDEX_NAME FROM ALL_INDEXES WHERE TABLE_NAME = 'NOTE';
I get:
INDEX_NAME
----------
IDX_FK_A_TABLE_NAME
SYS_C0044692561

Double check you indexed columns by querying ALL_IND_COLUMN (or DBA_IND_COLUMNS if you have acess). It will show you what table columns are indexed by which index.
SELECT c.index_owner, c.index_name, c.table_owner, c.table_name, c.column_name, c.column_position
FROM all_ind_columns c
WHERE c.table_owner = 'SCHEMA_NAME'
AND c.table_name = 'NOTE'
ORDER BY c.index_owner, c.index_name, c.column_position;
On a site note, When you are creating your indexes you're not prefixing them with a schema owner (CREATE INDEX SCHEMA.IDX_FK_A_TABLE_NAME ...). That means they're being created in your current schema. On the other hand, it's probably not related to the error you are facing.

Related

Generate DDL with Oracle Sql Developer to include Foreign keys

I Tried a few options to generate DDL from oracle database using SQL Developer and none of them fit the purpose.
The Quick DDL option results in DDL without Foreign Key constraints. I do like the format
The Edit on table results in DDL including storage and loggings which I cannot get rid of.
Just wondering anyone have better way of generating DDL using SQL Developer?
Thanks
The Quick DDL doesn't use any sort of preferences, it does it by what we think is appropriate - which is totally subjective of course.
However, if you go to the SQL page for an object in the tree, the DDL will be generated following the preferences set in Preferences > Database > Export.
For version 4.2, you can also use the DDL command in the worksheet. And you can use SET DDL to turn off or on the type of DDL you want generated.
SET DDL PRETTY ON;
SET DDL CONSTRAINTS ON;
SET DDL REF_CONSTRAINTS ON;
SET DDL PARTITIONING ON;
SET DDL TABLESPACE OFF;
SET DDL SEGMENT_ATTRIBUTES OFF;
SET DDL STORAGE OFF;
DDL EMPLOYEES
DDL Option CONSTRAINTS on
DDL Option REF_CONSTRAINTS on
DDL Option PARTITIONING on
DDL Option TABLESPACE off
DDL Option SEGMENT_ATTRIBUTES off
DDL Option STORAGE off
DDL Option STORAGE off
CREATE TABLE "HR"."EMPLOYEES"
( "EMPLOYEE_ID" NUMBER(6,0),
"FIRST_NAME" VARCHAR2(20),
"LAST_NAME" VARCHAR2(25) CONSTRAINT "EMP_LAST_NAME_NN" NOT NULL ENABLE,
"EMAIL" VARCHAR2(25) CONSTRAINT "EMP_EMAIL_NN" NOT NULL ENABLE,
"PHONE_NUMBER" VARCHAR2(20),
"HIRE_DATE" DATE CONSTRAINT "EMP_HIRE_DATE_NN" NOT NULL ENABLE,
"JOB_ID" VARCHAR2(10) CONSTRAINT "EMP_JOB_NN" NOT NULL ENABLE,
"SALARY" NUMBER(8,2),
"COMMISSION_PCT" NUMBER(2,2),
"MANAGER_ID" NUMBER(6,0),
"DEPARTMENT_ID" NUMBER(4,0),
CONSTRAINT "EMP_SALARY_MIN" CHECK (salary > 0) ENABLE,
CONSTRAINT "EMP_EMAIL_UK" UNIQUE ("EMAIL")
USING INDEX ENABLE,
CONSTRAINT "EMP_EMP_ID_PK" PRIMARY KEY ("EMPLOYEE_ID")
USING INDEX ENABLE,
CONSTRAINT "EMP_DEPT_FK" FOREIGN KEY ("DEPARTMENT_ID")
REFERENCES "HR"."DEPARTMENTS" ("DEPARTMENT_ID") ENABLE,
CONSTRAINT "EMP_JOB_FK" FOREIGN KEY ("JOB_ID")
REFERENCES "HR"."JOBS" ("JOB_ID") ENABLE,
CONSTRAINT "EMP_MANAGER_FK" FOREIGN KEY ("MANAGER_ID")
REFERENCES "HR"."EMPLOYEES" ("EMPLOYEE_ID") ENABLE
) ;
COMMENT ON COLUMN "HR"."EMPLOYEES"."EMPLOYEE_ID" IS 'Primary key of employees table.';
COMMENT ON COLUMN "HR"."EMPLOYEES"."FIRST_NAME" IS 'First name of the employee. A not null column.';
COMMENT ON COLUMN "HR"."EMPLOYEES"."LAST_NAME" IS 'Last name of the employee. A not null column.';
COMMENT ON COLUMN "HR"."EMPLOYEES"."EMAIL" IS 'Email id of the employee';
COMMENT ON COLUMN "HR"."EMPLOYEES"."PHONE_NUMBER" IS 'Phone number of the employee; includes country code and area code';
COMMENT ON COLUMN "HR"."EMPLOYEES"."HIRE_DATE" IS 'Date when the employee started on this job. A not null column.';
COMMENT ON COLUMN "HR"."EMPLOYEES"."JOB_ID" IS 'Current job of the employee; foreign key to job_id column of the
jobs table. A not null column.';
COMMENT ON COLUMN "HR"."EMPLOYEES"."SALARY" IS 'Monthly salary of the employee. Must be greater
than zero (enforced by constraint emp_salary_min)';
COMMENT ON COLUMN "HR"."EMPLOYEES"."COMMISSION_PCT" IS 'Commission percentage of the employee; Only employees in sales
department elgible for commission percentage';
COMMENT ON COLUMN "HR"."EMPLOYEES"."MANAGER_ID" IS 'Manager id of the employee; has same domain as manager_id in
departments table. Foreign key to employee_id column of employees table.
(useful for reflexive joins and CONNECT BY query)';
COMMENT ON COLUMN "HR"."EMPLOYEES"."DEPARTMENT_ID" IS 'Department id where employee works; foreign key to department_id
column of the departments table';
COMMENT ON TABLE "HR"."EMPLOYEES" IS 'employees table. Contains 107 rows. References with departments,
jobs, job_history tables. Contains a self reference.';
CREATE INDEX "HR"."EMP_DEPARTMENT_IX" ON "HR"."EMPLOYEES" ("DEPARTMENT_ID")
;
CREATE INDEX "HR"."EMP_JOB_IX" ON "HR"."EMPLOYEES" ("JOB_ID")
;
CREATE INDEX "HR"."EMP_MANAGER_IX" ON "HR"."EMPLOYEES" ("MANAGER_ID")
;
CREATE INDEX "HR"."EMP_NAME_IX" ON "HR"."EMPLOYEES" ("LAST_NAME", "FIRST_NAME")
;
CREATE INDEX "HR"."EMP_NAME_UPPER" ON "HR"."EMPLOYEES" (UPPER("LAST_NAME"))
;
CREATE OR REPLACE EDITIONABLE TRIGGER "HR"."UPDATE_JOB_HISTORY"
AFTER UPDATE OF job_id, department_id ON employees
FOR EACH ROW
BEGIN
add_job_history(:old.employee_id, :old.hire_date, sysdate,
:old.job_id, :old.department_id);
END;
/
ALTER TRIGGER "HR"."UPDATE_JOB_HISTORY" DISABLE;
CREATE OR REPLACE EDITIONABLE TRIGGER "HR"."SECURE_EMPLOYEES"
BEFORE INSERT OR UPDATE OR DELETE ON employees
BEGIN
secure_dml;
END secure_employees;
/
ALTER TRIGGER "HR"."SECURE_EMPLOYEES" DISABLE;

Alter table enable novalidate constraint

I am trying to add UNIQUE KEY on a previously existing table with duplicate records by setting ENABLE NOVALIDATE.
But I am getting ORA-02299: cannot validate (my_owner.my_key_UK ) - duplicate keys found
ALTER TABLE my_owner.my_table
ADD CONSTRAINT my_key_UK UNIQUE (ID1,ID2)
ENABLE NOVALIDATE;
A unique constraint uses an index to enforce the noduplicates rule. By default it will create a unique index (makes sense right?). It is this index creation which is hurling ORA-02299.
However, if this is an existing index on the constrained columns the constraint will use that. The good news is, the index doesn't need to be unique for the constraint to use it.
So what you need to do is build a non-unique index first:
create index whatever_idx on my_table (ID1,ID2);
Then you will be able to create your constraint:
ALTER TABLE my_owner.my_table
ADD CONSTRAINT my_key_UK UNIQUE (ID1,ID2)
ENABLE NOVALIDATE;
You can check this by querying the data dictionary:
select uc.constraint_name
, uc.constraint_type
, uc.index_name
, ui.uniqueness as idx_uniqueness
from user_constraints uc
join user_indexes ui
on ui.index_name = uc.index_name
where uc.table_name = 'MY_TABLE'
Oracle ensure unique values using indexes. And if you create unique constrains db automatic creates unique index. Workaround is add DEFERRABLE options. In this case oracle creates normal index. Check example.
create table table_abc (a number,b number);
insert into table_abc values(1,1);
insert into table_abc values(1,2);
ALTER TABLE table_abc ADD CONSTRAINT my_key_a UNIQUE (a) DEFERRABLE enable novalidate; -- no error but in table nonunique values
ALTER TABLE table_abc ADD CONSTRAINT my_key_b UNIQUE (b) ENABLE NOVALIDATE; --no error
select * from user_indexes where table_name ='TABLE_ABC';

Do I need to drop a foreign key on one table to delete a row on another using oracle?

I have two tables
Parent table
(account_number varchar(15) not null,
branch_name varchar(50) not null,
balance number not null,
primary key(account_number));
Child table
account_number varchar(15) not null,
foreign key(account_number) references parent table(account_number));
I am trying this:
DELETE FROM parent table
WHERE balances > 1000;
I am deleting accounts by balances on the parent but I get an error message about the child relationship.
My assumption is a DELETE CASCADE has to be added to the foreign key in the child table. All the documentation shows how to alter the table when the constraint is named. I do not have that situation. Is there a way to do it, or do I have to specify the cascade in the delete statement I am writing?
Every constraint in Oracle has a name. If a name isn't specified when the constraint is created, Oracle will autogenerate a name for the constraint. If you don't know what the name of a constraint is, try running a SQL statement that violates the constraint and reading the constraint name from the error message:
SQL> delete from parent where account_number = 1234;
delete from parent where account_number = 1234
*
ERROR at line 1:
ORA-02292: integrity constraint (LUKE.SYS_C007357) violated - child record
found
In this case the name of the constraint is SYS_C007357.
If that doesn't work, you can query the data dictionary view user_constraints:
SQL> select constraint_name from user_constraints where table_name = 'CHILD' and constraint_type = 'R';
CONSTRAINT_NAME
------------------------------
SYS_C007357
As far as I can tell, you can't modify a foreign key constraint to enable ON DELETE CASCADE. Instead you must drop the constraint and recreate it.
I don't believe you can apply the CASCADE option to a DELETE statement either, but you can delete the child rows before deleting from the parent:
DELETE FROM child
WHERE account_number IN (SELECT account_number FROM parent WHERE balance > 1000);
DELETE FROM parent
WHERE balance > 1000;
However, I don't know how many other tables you have with foreign key constraints referencing your parent table, nor in how many places you are deleting from the parent table, so I can't say how much work it would be to use this approach.
yes you can set DELETE CASCADE
see more info here FOREIGN KEYS WITH CASCADE DELETE
CREATE TABLE table_name
(
column1 datatype null/not null,
column2 datatype null/not null,
...
CONSTRAINT fk_column
FOREIGN KEY (column1, column2, ... column_n)
REFERENCES parent_table (column1, column2, ... column_n)
ON DELETE CASCADE
);
for example
CREATE TABLE supplier
( supplier_id numeric(10) not null,
supplier_name varchar2(50) not null,
contact_name varchar2(50),
CONSTRAINT supplier_pk PRIMARY KEY (supplier_id)
);
CREATE TABLE products
( product_id numeric(10) not null,
supplier_id numeric(10) not null,
CONSTRAINT fk_supplier
FOREIGN KEY (supplier_id)
REFERENCES supplier(supplier_id)
ON DELETE CASCADE
);

how to modify a constraint in sql plus?

I have created a table as follows:
create table emp( emp_id number(5) primary key
, emp_name varchar(20) not null
, dob date );
After the table has been created how would I change the constraint not null to unique or any other constraint in SQL*Plus?
You don't change a constraint from one type to another. You can add a unique constraint to the table
ALTER TABLE emp
ADD ( COSTRAINT uk_emp_name UNIQUE( emp_name ) );
That is independent of whether emp_name is allowed to have NULL values.
Just use ALTER TABLE command. For details look here: http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_3001.htm#i2103817
We cant be able to modify the already added constraint. Just we have to drop the constraint and add the new one with the same name, but add it with the necessary changes.
ALTER TABLE table_name drop constraint contraint_name;
alter table tablename add constraint containt_name CHECK (column_name IN (changes in the contraint)) ENABLE;

shrinking a column in oracle

Lets say i have a table with the following definition
create table dummy (col1 number(9) not null)
All the values in this dummy.col1 are 7 digit long. Now i want to reduce the length of this column from 9 - 7 using alter command. Oracle gives me error that column to be modified must be empty to decrease precision or scale. Makes sense.
I want to ask is there any work around to reduce the column size?
I can't delete the values in the column.
I can't copy values from this column to another since it has trillions of data.
The column size has no relationship to how the data is physically stored (they are variable length)
e.g. '23' in a number(2) will take exactly the same space if stored in a number(38)
It is purely a constraint on the maximum number that can be stored in the column therefore you could just add a constraint on the column:
ALTER TABLE dummy ADD
CONSTRAINT c1
CHECK (col1 < 9999999)
ENABLE
VALIDATE;
if you want it to go a little quicker change VALIDATE to NOVALIDATE obviously this will not check the validity of the existing data.
Kevin's answer is excellent.
The only other way to do it is to
rename the existing column,
create a new column with the old name and the new size,
issue an update statement to populate the new field (which you said you cannot do)
and then drop the renamed column.
Are you sure you cannot find some downtime one weekend to perform this task ?
Solution #1
My solution below keeps the original column order.
I found that to be important, especially if there are canned SQL statements out
there (middle tier, client tier) that point back to your database that do implicit
SELECTs.
i.e.
SELECT *
FROM tableName
WHERE ...;
INSERT INTO copyTableName(column1,column2,column3,...)
SELECT *
FROM tableName
WHERE ...;
Here goes:
Generate the DDLs for
1. The table containing the column you intend to resize
2. All the relationship constraints, indexes, check constraints, triggers that reference that table.
3. All the foreign keys of other tables that reference the primary key of this table.
Make sure each table-referencing-object DDL is stand-alone, separate from the
CREATE TABLE DDL.
You'll have something like
/* 1. The table containing the column you intend to resize */
CREATE TABLE tableName
(
column1 TYPE(size) [DEFAULT value] [NOT] NULL,
column2 TYPE(size) [DEFAULT value] [NOT] NULL,
column3 TYPE(size) [DEFAULT value] [NOT] NULL,
...
)
TABLESPACE tsName
[OPTIONS];
/* 2. All the relationship constraints, indexes, check constraints, triggers that reference that table. */
CREATE INDEX indexName ON tableName
(column1)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
CREATE INDEX compositeIndexName ON tableName
(column1,column2,...)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
CREATE UNIQUE INDEX pkName ON tableName
(column2)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
ALTER TABLE tableName ADD (
CHECK (column4 IS NOT NULL));
ALTER TABLE tableName ADD (
CONSTRAINT pkName
PRIMARY KEY
(column2)
USING INDEX
TABLESPACE INDX);
ALTER TABLE tableName ADD (
CONSTRAINT fkName
FOREIGN KEY (column2)
REFERENCES otherTable (column2));
/* 3. All the foreign keys of other tables that reference the primary key of this table. */
ALTER TABLE otherTableName ADD (
CONSTRAINT otherTableFkName
FOREIGN KEY (otherTableColumn2)
REFERENCES tableName (column1));
Copy out just the CREATE TABLE statement, change the table name and
reduce the size of the column you wish to modify:
CREATE TABLE tableName_YYYYMMDD
(
column1 TYPE(size) [DEFAULT value] [NOT] NULL,
column2 TYPE(reducedSize) [DEFAULT value] [NOT] NULL,
column3 TYPE(size) [DEFAULT value] [NOT] NULL,
...
)
TABLESPACE tsName
[OPTIONS];
Insert the data from tableName into tableName_YYYYMMDD:
INSERT /* APPEND */ INTO tableName_YYYYMMDD(
column1 ,
column2 ,
column3 ,
... )
SELECT
column1 ,
column2 ,
column3 ,
...
FROM tableName;
COMMIT;
Drop all objects referencing the original table.
Also, drop all foreign keys that reference the tableName primary key pkName.
Don't worry, you've saved the DDL so you'll be able to recreate them.
Notice that I drop indexes after copying the data out of tableName.
I do this because perhaps one of the indexes will be used in the
above SELECT so that operation will complete faster.
DROP INDEX indexName ;
DROP INDEX compositeIndexName ;
DROP UNIQUE INDEX pkName ;
ALTER TABLE tableName DROP CONSTRAINT pkName ;
ALTER TABLE tableName DROP CONSTRAINT fkName ;
ALTER TABLE otherTableName DROP CONSTRAINT otherTableFkName ;
Drop the original table.
DROP TABLE tableName;
Rename the new table.
ALTER TABLE tableName_YYYYMMDD RENAME TO tableName;
Recreate all referencing objects from the DDL statements you saved before.
/* 2. All the relationship constraints, indexes, check constraints, triggers that reference that table. */
CREATE INDEX indexName ON tableName
(column1)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
CREATE INDEX compositeIndexName ON tableName
(column1,column2,...)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
CREATE UNIQUE INDEX pkName ON tableName
(column2)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
ALTER TABLE tableName ADD (
CHECK (column4 IS NOT NULL));
ALTER TABLE tableName ADD (
CONSTRAINT pkName
PRIMARY KEY
(column2)
USING INDEX
TABLESPACE INDX);
ALTER TABLE tableName ADD (
CONSTRAINT fkName
FOREIGN KEY (column2)
REFERENCES otherTable (column2));
/* 3. All the foreign keys of other tables that reference the primary key of this table. */
ALTER TABLE otherTableName ADD (
CONSTRAINT otherTableFkName
FOREIGN KEY (otherTableColumn2)
REFERENCES tableName (column1));
Solution #2
Keep the column order but do not rebuild non-unique-used-by-PK indexes that might contain column2.
ALTER TABLE tableName ADD (column2Copy TYPE(reducedSize));
UPDATE tableName SET column2Copy = column2;
ALTER TABLE tableName MODIFY (column2 TYPE(size) NULL);
ALTER TABLE tableName DROP CONSTRAINT pkName;
DROP INDEX pkName;
UPDATE tableName SET column2 = null;
ALTER TABLE tableName MODIFY (column2 TYPE(reducedSize));
UPDATE tableName SET column2 = column2Copy;
ALTER TABLE tableName DROP COLUMN column2Copy;
CREATE UNIQUE INDEX pkName ON tableName
(column2)
NOLOGGING
TABLESPACE INDX
NOPARALLEL;
ALTER TABLE tableName ADD (
CONSTRAINT pkName
PRIMARY KEY
(column2)
USING INDEX
TABLESPACE INDX);
COMMIT;

Resources