Replacing certain lines in a statemement - oracle

I am exporting ddl statemements for tables using dbms_metadata.set_transform_param package. This works as intended. However, I am also interested to remove a certain lines from the output.
For example: here is the output of one of the tables:
CREATE TABLE "FREEZES"
( "PLAYER_ID" NUMBER(9,0) NOT NULL ENABLE,
"PRODUCT_ID" NUMBER(19,0)
)
TABLESPACE "MINE" ;
ALTER TABLE "FREEZES" ADD CONSTRAINT "FREEZES_U" UNIQUE ("PLAYER_ID", "PRODUCT_ID")
USING INDEX
TABLESPACE "MINE_IDX" ENABLE;
ALTER TABLE "FREEZES" ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY) COLUMNS;
ALTER TABLE "FREEZES" ADD SUPPLEMENTAL LOG DATA (FOREIGN KEY) COLUMNS;
ALTER TABLE "FREEZES" ADD SUPPLEMENTAL LOG DATA (UNIQUE INDEX) COLUMNS;
ALTER TABLE "FREEZES" ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS;
What I would like to have is:
CREATE TABLE "FREEZES"
( "PLAYER_ID" NUMBER(9,0) NOT NULL ENABLE,
"PRODUCT_ID" NUMBER(19,0)
)
TABLESPACE "MINE" ;
ALTER TABLE "FREEZES" ADD CONSTRAINT "FREEZES_U" UNIQUE ("PLAYER_ID", "PRODUCT_ID")
USING INDEX
TABLESPACE "MINE_IDX" ENABLE;
And here is the query I am using:
SELECT dbms_metadata.get_ddl(object_type, object_name, owner) as object_ddl
from dba_objects where owner = 'MINE' and object_type = 'TABLE';
I do know that I have to use regular expressions, something like:
SELECT regexp_replace(dbms_metadata.get_ddl(object_type, object_name, owner), 'pattren') as object_ddl
from dba_objects where owner = 'MINE' and object_type = 'TABLE';

Related

In oracle on delete set null is not working

I have created two tables:
Create Table Dept
(Department_id number Constraint Depart_id_pk Primary Key
,Department_name varchar2(20));
Create table Emp
(Emp_id number Constraint Empl_id_pk Primary Key
,First_name varchar2(10)
,salary number
,Department_id number
,Constraint depart_id_fk Foreign Key (department_id)
References Dept (Department_id) on delete set null);
Then I have inserted some records in dept and Emp table. But when I try to drop dept table, instead of setting null in Emp.department_id column it shows error like this:
SQL> Drop Table Dept;
Drop Table Dept
*
ERROR at line 1:
ORA-02449: unique/primary keys in table referenced by foreign keys
The foreign key's clause say "on delete set null". Delete is a DML operation, and had you attempted to delete rows from the dept table, the corresponding emp rows would have been updated with a null dept_id.
But this isn't the case - you tried to drop the entire table, a DDL operation. This isn't allowed, because you'd be leaving behind constraints on the emp table that reference a table that no longer exists. If you want to drop these constraints too, you can use a cascade constraints clause:
DROP TABLE dept CASCADE CONSTRAINTS

Table tablespace shown as X but appears to be 'Users'

I am using SQL*Plus to create a table with the following sql:
CREATE TABLE SCHEMA_OWNER.TEST_TABLE (
ID NUMBER(19,0) NOT NULL,
TEST_STRING VARCHAR2(255 CHAR),
PRIMARY KEY (ID)
);
When I try and do an insert with any user into that table, I see the following error:
INSERT INTO TEST_TABLE (ID, TEST_STRING) values (1, 'Test')
ORA-01950: no privileges on tablespace 'USERS'
This implies that the table has been created in the Users tablespace, but when I look in the USER_TABLES table, I see that the tablespace is the same as all of the other tables, and not 'Users':
SELECT table_name, tablespace_name from USER_TABLES;
TABLE_NAME TABLESPACE_NAME
---------------- ---------------
TABLE1 DATA_TABLESPACE
TEST_TABLE DATA_TABLESPACE
When I create the table in SQL developer using the same SQL, I don't have any errors when inserting data.
1) Why am I getting this error when the table isn't in the Users tablespace?
2) Why am I only getting it when running the sql script from SQL*Plus?
Thanks to Aleksej for suggesting it could be an issue with the indexes. The problem was that when I was creating the index on the table, I wasn't creating it for the schema owner, which meant that it was being created in a different tablespace.
So instead of
CREATE INDEX TEST_TABLE_IDX ON SCHEMA_OWNER.TEST_TABLE(TEST_STRING);
I needed to do
CREATE INDEX SCHEMA_OWNER.TEST_TABLE_IDX ON SCHEMA_OWNER.TEST_TABLE(TEST_STRING);

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;

Oracle: ORA-01408: such column list already indexed

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.

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