updating partition Key, row movement not allowed - oracle

i want to update a partition key. the partition is as below
PARTITION_NAME LAST_ANALYZED NUM_ROWS BLOCKS SAMPLE_SIZE HIGH_VALUE
PORTAL_SERVICE_1 12/8/2016 4133 174 4133 1
PORTAL_SERVICE_2 6/8/2016 4474 174 4474 2
PORTAL_SERVICE_3 10/8/2016 29602 2014 29602 3
PORTAL_SERVICE_OTHERS 24/5/2016 0 110 DEFAULT
this partition is applied on column Portal_Service_id. i want to update the value of portal service id from 2 to 1.
when i try
update trans set PORTAL_SERVICE_ID = 1 where ID = 2054;
i get error:
Error report -
SQL Error: ORA-14402: updating partition key column would cause a partition change
14402. 00000 - "updating partition key column would cause a partition change"
i am not allowed to use Enable Row Movement.
Can anybody please suggest any alternative to update the row.
can anybody shed some light if this can be used in the scenario:
UPDATE <table_name> PARTITION (<partition_name>)
SET <column_name> = <value>
WHERE <column_name> <condition> <value>;

to work around the error "ORA-14402: updating partition key column would cause a partition change" you can follow these steps
1) Check if for your table is enabled the row_movement
SELECT owner,
table_name,
row_movement
FROM dba_tables
WHERE table_name in ('YOUR_TABLE');
2) If is disabled you can enable movement with this script
alter table YOUR_TABLE enable row movement;
After that you can update the partition key column

Most of the other answers have pointed out one part of the solution, which is:
alter table <table_name> enable row movement
However, there's more to it than this. Enabling row movement has some tradeoffs, which are pointed out here: http://www.dba-oracle.com/t_enable_row_movement.htm
In my case, this led me to double check why we were using a partition in the first place. Ideally, a partition is for data that won't move around once it's in the partition. If you're modifying the partition field (in my case a timestamp) then it may mean you shouldn't be using a partition. If you're sure you want a partition on a mutable field, then at least make sure you periodically run:
"alter table shrink compact"

I came across this question as the top Google result when searching for ORA-14402. In my particular case I:
exported the rows as insert statements
updated the index key field and updated the ID field
inserted the rows as new rows.
You could then potentially delete the old rows if you have the need or leave them in the old partition.

Enable row movement with this syntex , it will solve the error :
alter table <table_name> enable row movement

Related

Dealing with Oracle ARCHIVELOG during huge updates

It's required to update columns with metadata globally in all rows of all tables in DB. Let's say every table has a column MY_META and the aim is roughly
update ANOTHER_TABLE set MY_META = 'HELLO'
for each table.
Estimated total rows count is 2e9.
Suppose ARCHIVELOG mode is on, so during those updates a lot of extra space is going to be consumed.
The process of updates is planned to be running in production DB simultaneously with business transactions, which should not be lost.
The simplest thing to start with is temporarily installing plenty of hardware for ARCHIVELOG files.
Is there an elegant way to achieve the same goal programmatically or via tuning "secret options"?
Since your clarifications, I understand that:
for each table, you have a value of MY_META that you want to assign to each row as an initial value.
you don't mind dropping MY_META and recreating it.
In this case, I would suggest that you drop MY_META and recreate it with a default value. If you do this, Oracle will not update every record with your initial value and the amount of redo generated will be minimal.
The downside is that the ALTER TABLE commands, though very fast, will briefly lock each table as you process it. It will also invalidate packages that depend on the MY_META column.
Here is a walkthrough of the approach, with comments:
-- Set up your current state
DROP TABLE my_big_table;
CREATE TABLE my_big_table (a number, my_meta varchar2(30) not null);
INSERT INTO my_big_table (a, my_meta) SELECT rownum, 'GARBAGE' FROM dual CONNECT BY rownum <= 100000;
-- Drop the my_meta column and replace it with one having a default value
ALTER TABLE my_big_table DROP COLUMN my_meta;
ALTER TABLE my_big_table ADD my_meta varchar2(30) default 'INITIAL_VAL_FOR_TABLE' not null;
-- Look at my table -- you will see every row has your initial value
SELECT * FROM my_big_table;
-- Update some data
update my_big_table set my_meta = 'UPDATED_VALUE' WHERE a <= 15;
-- Look at my table -- you will see every row has your initial value except the first 15.
SELECT * FROM my_big_table order by a;

oracle how to alter table add partition by range interval

i have searched a lot but i have found nothing about how to
add a range partition to an existing table
alter table myuser.mytable
add PARTITION BY RANGE (mynumber) INTERVAL (1)
( PARTITION p1 VALUES LESS THAN (108))
that gives me ORA:14150 error, SUBPARTITON keyword is missing,
but i dont want to give subpartition
EDIT: On 19c and 12cR2 this can be done using the MODIFY Clause of ALTER TABLE
ALTER TABLE myuser.mytable MODIFY
PARTITION BY RANGE (mynumber) INTERVAL (1)
( PARTITION p1 VALUES LESS THAN (108)
PARTITION p2 VALUES LESS THAN (109))
ONLINE
UPDATE INDEXES
See this from Oracle Docs
PRIOR To 19c or 12cR2:
If your existing Table is Non-Partitioned you will have to:
CREATE a new TABLE with partition definitions. Lets call this table MYTABLE_NEW
INSERT into MYTABLE_NEW all data from MYTABLE
RENAME MYTABLE to MYTABLE_OLD
RENAME MYTABLE_NEW to MYTABLE
DROP MYTABLE_OLD
OR
dbms_redefinition can also be used
See this from AskTom
Also see this other Answer

Oracle - Delete One Row in Dimension Table is Slow

I have a datamart with 5 dimension table and a fact table.
I'm trying to clean a dimension table that has few rows (4000 rows). But, the fact table have millions rows (25GB)(Indexes and partitions).
When I try to delete a row in the table dimension, the process becomes very slow. It's just as slow despite the absence of relationship with a row in the fact table (cascade delete).
Is there any way to optimize this?. Thanks in advance.
Presumably, there is a cascading delete of some sort between the dimension table and the fact table.
Adding an index on the key column in the fact table may be sufficient. Then Oracle can immediately tell if/where any given value is.
If that doesn't work, drop the foreign key constraint altogether. Delete the unused values and add the constraint back in.
You could try these strategies as well :
create another copy of the fact table but, without the dim foreign key column of the table to be cleaned.
create fact_table_new as
select dim1_k, dim2_k, dim3_k, dim4_k, dim5_k (not this column), fact_1, fact_2, ...
from fact_table ;
or
update fact_table
set dim5_fk_col = null
where dim5_fk_col in (select k_col from dim5_table) ;

Oracle Trigger for incrementing Integer value [duplicate]

This question already has answers here:
How to create id with AUTO_INCREMENT on Oracle?
(18 answers)
Closed 7 years ago.
I want to add a new auto increment primary column to a existing table which has data. How do I do that?
I first added a column and then try to add a sequence after that, I lost how to insert and make that column as primary key.
Say your table is called t1 and your primary-key is called id
First, create the sequence:
create sequence t1_seq start with 1 increment by 1 nomaxvalue;
Then create a trigger that increments upon insert:
create trigger t1_trigger
before insert on t1
for each row
begin
select t1_seq.nextval into :new.id from dual;
end;
If you have the column and the sequence, you first need to populate a new key for all the existing rows. Assuming you don't care which key is assigned to which row
UPDATE table_name
SET new_pk_column = sequence_name.nextval;
Once that's done, you can create the primary key constraint (this assumes that either there is no existing primary key constraint or that you have already dropped the existing primary key constraint)
ALTER TABLE table_name
ADD CONSTRAINT pk_table_name PRIMARY KEY( new_pk_column )
If you want to generate the key automatically, you'd need to add a trigger
CREATE TRIGGER trigger_name
BEFORE INSERT ON table_name
FOR EACH ROW
BEGIN
:new.new_pk_column := sequence_name.nextval;
END;
If you are on an older version of Oracle, the syntax is a bit more cumbersome
CREATE TRIGGER trigger_name
BEFORE INSERT ON table_name
FOR EACH ROW
BEGIN
SELECT sequence_name.nextval
INTO :new.new_pk_column
FROM dual;
END;
Snagged from Oracle OTN forums
Use alter table to add column, for example:
alter table tableName add(columnName NUMBER);
Then create a sequence:
CREATE SEQUENCE SEQ_ID
START WITH 1
INCREMENT BY 1
MAXVALUE 99999999
MINVALUE 1
NOCYCLE;
and, the use update to insert values in column like this
UPDATE tableName SET columnName = seq_test_id.NEXTVAL
You can use the Oracle Data Modeler to create auto incrementing surrogate keys.
Step 1. - Create a Relational Diagram
You can first create a Logical Diagram and Engineer to create the Relational Diagram or you can straightaway create the Relational Diagram.
Add the entity (table) that required to have auto incremented PK, select the type of the PK as Integer.
Step 2. - Edit PK Column Property
Get the properties of the PK column.
You can double click the name of the column or click on the 'Properties' button.
Column Properties dialog box appears.
Select the General Tab (Default Selection for the first time).
Then select both the 'Auto Increment' and 'Identity Column' check boxes.
Step 3. - Additional Information
Additional information relating to the auto increment can be specified by selecting the 'Auto Increment' tab.
Start With
Increment By
Min Value
Max Value
Cycle
Disable Cache
Order
Sequence Name
Trigger Name
Generate Trigger
It is usually a good idea to mention the sequence name, so that it will be useful in PL/SQL.
Click OK (Apply) to the Column Properties dialog box.
Click OK (Apply) to the Table Properties dialog box.
Table appears in the Relational Diagram.

Add a auto increment primary key to existing table in oracle [duplicate]

This question already has answers here:
How to create id with AUTO_INCREMENT on Oracle?
(18 answers)
Closed 7 years ago.
I want to add a new auto increment primary column to a existing table which has data. How do I do that?
I first added a column and then try to add a sequence after that, I lost how to insert and make that column as primary key.
Say your table is called t1 and your primary-key is called id
First, create the sequence:
create sequence t1_seq start with 1 increment by 1 nomaxvalue;
Then create a trigger that increments upon insert:
create trigger t1_trigger
before insert on t1
for each row
begin
select t1_seq.nextval into :new.id from dual;
end;
If you have the column and the sequence, you first need to populate a new key for all the existing rows. Assuming you don't care which key is assigned to which row
UPDATE table_name
SET new_pk_column = sequence_name.nextval;
Once that's done, you can create the primary key constraint (this assumes that either there is no existing primary key constraint or that you have already dropped the existing primary key constraint)
ALTER TABLE table_name
ADD CONSTRAINT pk_table_name PRIMARY KEY( new_pk_column )
If you want to generate the key automatically, you'd need to add a trigger
CREATE TRIGGER trigger_name
BEFORE INSERT ON table_name
FOR EACH ROW
BEGIN
:new.new_pk_column := sequence_name.nextval;
END;
If you are on an older version of Oracle, the syntax is a bit more cumbersome
CREATE TRIGGER trigger_name
BEFORE INSERT ON table_name
FOR EACH ROW
BEGIN
SELECT sequence_name.nextval
INTO :new.new_pk_column
FROM dual;
END;
Snagged from Oracle OTN forums
Use alter table to add column, for example:
alter table tableName add(columnName NUMBER);
Then create a sequence:
CREATE SEQUENCE SEQ_ID
START WITH 1
INCREMENT BY 1
MAXVALUE 99999999
MINVALUE 1
NOCYCLE;
and, the use update to insert values in column like this
UPDATE tableName SET columnName = seq_test_id.NEXTVAL
You can use the Oracle Data Modeler to create auto incrementing surrogate keys.
Step 1. - Create a Relational Diagram
You can first create a Logical Diagram and Engineer to create the Relational Diagram or you can straightaway create the Relational Diagram.
Add the entity (table) that required to have auto incremented PK, select the type of the PK as Integer.
Step 2. - Edit PK Column Property
Get the properties of the PK column.
You can double click the name of the column or click on the 'Properties' button.
Column Properties dialog box appears.
Select the General Tab (Default Selection for the first time).
Then select both the 'Auto Increment' and 'Identity Column' check boxes.
Step 3. - Additional Information
Additional information relating to the auto increment can be specified by selecting the 'Auto Increment' tab.
Start With
Increment By
Min Value
Max Value
Cycle
Disable Cache
Order
Sequence Name
Trigger Name
Generate Trigger
It is usually a good idea to mention the sequence name, so that it will be useful in PL/SQL.
Click OK (Apply) to the Column Properties dialog box.
Click OK (Apply) to the Table Properties dialog box.
Table appears in the Relational Diagram.

Resources