Drop a column from a Range Partitioned and Compressed table - oracle

I have a table with data and need to remove a column, which is marked as unused. But it gives the error due to the compressed table.
I have used the command
ALTER TABLE <table name> MOVE NOCOMPRESS NOLOGGING PARALLEL 4;
But it gives this error:
ORA-14511: cannot perform operation on a partitioned object
How can I disable the partitioned? And how can I remove the unused column?

No, you cannot move partitioned table with one alter table statement, you need to perform relocation of that table into a new segment partition by partition:
Create test table:
SQL> create table t1(
2 col1 number,
3 col2 number
4 )
5 partition by range(col1) (
6 partition p_1 values less than (10) compress,
7 partition p_2 values less than (20) compress
8 );
Table created.
Populate test table with some sample data:
SQL> insert into t1(col1, col2)
2 select level
3 , level
4 from dual
5 connect by level <= 3;
3 rows created.
SQL> commit;
Commit complete.
SQL> select * from t1;
COL1 COL2
---------- ----------
1 1
2 2
3 3
Drop column statement fails:
SQL> alter table t1 drop column col2;
alter table t1 drop column col2
*
ERROR at line 1:
ORA-39726: unsupported add/drop column operation on compressed tables
Table relocation fails:
SQL> alter table t1 move nocompress;
alter table t1 move nocompress
*
ERROR at line 1:
ORA-14511: cannot perform operation on a partitioned object
Perform relocation of each partition:
SQL> alter table t1 move partition p_1 nocompress;
Table altered.
SQL> alter table t1 move partition p_2 nocompress;
Table altered.
When there are too many partitions, you can easily generate alter table statements while querying user_tab_partitions data dictionary view. For example:
SQL> column res format a50
SQL> select 'alter table ' || t.table_name ||
2 ' move partition ' || t.partition_name ||
3 ' nocompress;' as res
4 from user_tab_partitions t
5 where t.table_name = 'T1';
RES
--------------------------------------------------
alter table T1 move partition P_1 nocompress;
alter table T1 move partition P_2 nocompress;
After you have moved all partitions with nocompress option, you can drop column(s) issuing:
alter table t1 drop column col2
statement, or
alter table t1 drop unused columns
statement, if you already marked column(s) as unused before relocation.
Dropping unused columns:
Make col2 unused
SQL> alter table t1 set unused(col2);
Table altered.
List tables with unused columns in our schema
SQL> column table_name format a5
SQL> column table_name format a5
SQL> select *
2 from user_unused_col_tabs;
TABLE COUNT
----- ----------
T1 1
Relocate partitions
SQL> alter table T1 move partition P_1 nocompress;
Table altered.
SQL> alter table T1 move partition P_2 nocompress;
Table altered.
Drop unused columns:
SQL> alter table t1 drop unused columns;
Table altered.
Make sure we dropped everything we wanted to drop. Col2 is gone:
SQL> desc t1;
Name Null? Type
-------- -------- -----------
COL1 NUMBER
There are no tables with unused columns:
SQL> select *
2 from user_unused_col_tabs;
no rows selected

Related

Creating List partition to an already Existing Table

I am trying to Create a list partition Based on the column "REFRESH_FLAG_Y" which has only Y and N as its Values, Below is the Alter Table used to Create the partition
ALTER TABLE "EDW"."LABOR_SCHEDULE_DAY_F" MODIFY
PARTITION BY LIST ("REFRESH_FLAG")
(PARTITION "REFRESH_FLAG_Y" VALUES ('Y') ,
PARTITION "REFRESH_FLAG_N" VALUES ('N')) ;
COMMIT;
But Whenever I execute the code I get an Error message
ERROR at line 1:
ORA-14400: inserted partition key does not map to any partition
You did tag the question with Oracle 11g tag; do you really use it?
This is a 12c example; it works if everything is OK:
SQL> create table labor_schedule_day_f as
2 select 1 id, 'Y' refresh_flag from dual union all
3 select 2 id, 'N' refresh_flag from dual;
Table created.
SQL> alter table labor_schedule_Day_f modify
2 partition by list (refresh_flag)
3 (partition refresh_flag_y values ('Y'),
4 partition refresh_flag_n values ('N')
5 );
Table altered.
Error you reported means this:
SQL> drop table labor_schedule_day_f;
Table dropped.
SQL> create table labor_schedule_day_f as
2 select 1 id, 'Y' refresh_flag from dual union all
3 select 2 id, 'N' refresh_flag from dual;
Table created.
Insert a row whose REFRESH_FLAG isn't Y nor N (so it violates the rule you specified):
SQL> insert into labor_schedule_day_f values (3, 'X');
1 row created.
Using the same ALTER TABLE statement as previously:
SQL> alter table labor_schedule_Day_f modify
2 partition by list (refresh_flag)
3 (partition refresh_flag_y values ('Y'),
4 partition refresh_flag_n values ('N')
5 );
alter table labor_schedule_Day_f modify
*
ERROR at line 1:
ORA-14400: inserted partition key does not map to any partition
SQL>
See? Error you got, which means that
which has only Y and N as its Values
isn't true.
P.S. You'd get the same result even if refresh_flag was NULL for some rows.

How to select partition name of specific data?

I want to select a data and wanna see in which partition.
partition column is : code (varchar column)
Select .... -- I want to find partition name
from
partition_table
where to_number(code) = 55;
why I need to this:
I have a data which code is '55' but in that table when I use partition column I do not select it. But there is data which value is '55'
So I want to that data in which partition.
And the data is not in PDEFAULT partition. I ve already check it.
edit
data is in another partition. I think there is a problem with exchange partition process
thanks in advance
There are a couple of ways.
1) The rowid will point to the partition object
SQL> create table t ( x int, y int )
2 partition by range (x )
3 ( partition p1 values less than ( 100 ),
4 partition p2 values less than ( 200 )
5 );
Table created.
SQL>
SQL> insert into t values (34,34);
1 row created.
SQL>
SQL> select rowid from t;
ROWID
------------------
AAA0cqAAHAAAAQ6AAA
1 row selected.
SQL>
SQL> select dbms_rowid.rowid_object(rowid) from t;
DBMS_ROWID.ROWID_OBJECT(ROWID)
------------------------------
214826
1 row selected.
SQL>
SQL> select subobject_name
2 from user_objects
3 where data_Object_id =
4 ( select dbms_rowid.rowid_object(rowid) from t );
SUBOBJECT_NAME
------------------------------------------------------------
P1
2) You can data mine the dictionary to probe the HIGH_VALUE column in USER_TAB_PARTITIONS. I did a video on how to do that here
https://www.youtube.com/watch?v=yKHQQXKdfOM

In Oracle, does the unique constraint include an index implicitly?

this question is for performance issue,
For example, if I would add a unique constraint such as:
ALTER TABLE Staffs ADD CONSTRAINT test UNIQUE (Company_Name, Staff_ID);
should I add a unique index for performance issue?
CREATE UNIQUE INDEX test2 ON Staffs (Company_Name, Staff_ID);
For Primary key, I can see there must be a corresponding index in dba_indexes system table,
but I have not seen the equivalent for the case unique constraint
"I have not seen the equivalent for the case unique constraint"
Hmmmm, are you sure?
SQL> create table t23
2 (id number
3 , col1 date)
4 /
Table created.
SQL> alter table t23
2 add constraint t23_uk unique (id)
3 /
Table altered.
SQL> select index_name, uniqueness
2 from user_indexes
3 where table_name='T23'
4 /
INDEX_NAME UNIQUENES
------------------------------ ---------
T23_UK UNIQUE
SQL>
Note that we can use an existing index, and it doesn't have to be unique. But this means the index name might not match the constraint name (this would also work for primary keys):
SQL> alter table t23 drop constraint t23_uk;
Table altered.
SQL> select index_name, uniqueness
2 from user_indexes
3 where table_name='T23'
4 /
no rows selected
SQL> create index t23_idx on t23(id)
2 /
Index created.
SQL> select index_name, uniqueness
2 from user_indexes
3 where table_name='T23'
4 /
INDEX_NAME UNIQUENES
------------------------------ ---------
T23_IDX NONUNIQUE
SQL> alter table t23
2 add constraint t23_uk unique (id)
3 /
Table altered.
SQL>
Does the non-unique index enforce the unique constraint? Yes it does:
SQL> insert into t23 values (1, sysdate)
2 /
1 row created.
SQL> r
1* insert into t23 values (1, sysdate)
insert into t23 values (1, sysdate)
*
ERROR at line 1:
ORA-00001: unique constraint (APC.T23_UK) violated
SQL> drop index t23_idx
2 /
drop index t23_idx
*
ERROR at line 1:
ORA-02429: cannot drop index used for enforcement of unique/primary key
SQL>
We can check the data dictionary to see which index is associated with a constraint:
SQL> select constraint_name, constraint_type, index_name
2 from user_constraints
3 where table_name = 'T23'
4 /
CONSTRAINT_NAME C INDEX_NAME
------------------------------ - ------------------------------
T23_UK U T23_IDX
SQL>

delete row by id

I'm in the middle of creating a tool similar to the SQL Developer table data viewer. My db is Oracle based.
I simply need to delete eg.: 'row number 3' from a SELECT result. That table doesn't have any PK nor unique records. I've tried various techniques with ROWNUM etc. but no luck.
Oracle has a ROWID pseudocolumn that you can use for this purpose in simple cases.
select rowid, ... from your_table where ... ;
delete from your_table where rowid = <what you got above>;
If your interface allows the user to make complex views/joins/aggregates, then knowing what the user intended to delete (so knowing what set of rowids to gather and what set of tables to delete from) is going to be tricky.
Warning: rowids are unique only within a given table, and, quoting the above documentation:
If you delete a row, then Oracle may reassign its rowid to a new row inserted later.
So be very, very careful if you do this.
Assuming that it is a standard heap-organized table (index-organized tables and clusters potentially introduce additional complexity), if you don't have any other way to identify a row, you can use the ROWID pseudocolumn. This gives you information about the physical location of a row on disk. This means that the ROWID for a particular row can change over time and the ROWID can and will be reused when you delete a row and then a subsequent INSERT operation inserts a new row that happens to be in the same physical location on disk. For most applications, it is reasonable to assume that the ROWID will remain constant between the time that you execute the query and the time that you issue the DELETE but you shouldn't try to store the ROWID for any period of time.
For example, if we create a simple two-column table and a few rows
SQL> create table foo( col1 number, col2 varchar2(10) );
Table created.
SQL> insert into foo values( 1, 'Justin' );
1 row created.
SQL> insert into foo values( 1, 'Justin' );
1 row created.
SQL> insert into foo values( 2, 'Bob' );
1 row created.
SQL> insert into foo values( 2, 'Charlie' );
1 row created.
SQL> commit;
Commit complete.
We can SELECT the ROWID and then DELETE the third row using the ROWID
SQL> select *
2 from foo;
COL1 COL2
---------- ----------
1 Justin
1 Justin
2 Bob
2 Charlie
SQL> select rowid, col1, col2
2 from foo;
ROWID COL1 COL2
------------------ ---------- ----------
AAAfKXAAEAABt7vAAA 1 Justin
AAAfKXAAEAABt7vAAB 1 Justin
AAAfKXAAEAABt7vAAC 2 Bob
AAAfKXAAEAABt7vAAD 2 Charlie
SQL> delete from foo where rowid = 'AAAfKXAAEAABt7vAAC';
1 row deleted.
SQL> select * from foo;
COL1 COL2
---------- ----------
1 Justin
1 Justin
2 Charlie
Try using ROWID instead of ROWNUM.

How can I import a partition from one table into another in Oracle?

I would like to know if the following steps are possible and how fast this is:
Create a partition named part1 in Table A
Drop partition part1 in Table B
Import the Table A partition part1 into Table B
Can you provide me with an example if it is possible indeed? Or any resources I can look at?
Note that the tables would have the exact same structure.
You can do something similar with the ALTER TABLE ... EXCHANGE PARTITION command. This would exchange a single partition with a table that has the same structure.
A little example:
/* Partitionned Table Creation */
SQL> CREATE TABLE table_a (
2 ID NUMBER PRIMARY KEY,
3 DATA VARCHAR2(200)
4 )
5 PARTITION BY RANGE (ID) (
6 PARTITION part100 VALUES LESS THAN (100),
7 PARTITION part200 VALUES LESS THAN (200)
8 );
Table created
/* Swap table creation */
SQL> CREATE TABLE swap_table (
2 ID NUMBER PRIMARY KEY,
3 DATA VARCHAR2(200)
4 );
Table created
SQL> INSERT INTO swap_table SELECT ROWNUM, 'a' FROM dual CONNECT BY LEVEL <= 99;
99 rows inserted
SQL> select count(*) from table_a partition (part100);
COUNT(*)
----------
0
This will exchange the partition part100 with the transition table swap_table:
SQL> ALTER TABLE table_a EXCHANGE PARTITION part100 WITH TABLE swap_table;
Table altered
SQL> select count(*) from table_a partition (part100);
COUNT(*)
----------
99

Resources