Skip to Main Content

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, S.

Asked: July 29, 2006 - 11:04 pm UTC

Last updated: January 16, 2023 - 3:21 am UTC

Version: 10g

Viewed 10K+ times! This question is

You Asked

Dear Tom,

Would it be possible to add or remove the columns from a Compressed table.

Thanks,
-sp

and Tom said...

Add, yes:

ops$tkyte%ORA10GR2> create table t compress as select * from all_users;

Table created.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> alter table t add x number;

Table altered.

physically drop, no:

ops$tkyte%ORA10GR2> alter table t drop column x;
alter table t drop column x
*
ERROR at line 1:
ORA-39726: unsupported add/drop column operation on compressed tables

but make it "disappear"
ops$tkyte%ORA10GR2> alter table t set unused column x;

Table altered.

yes, which if you ask me is OK since you would have to rewrite the entire segment to truly get rid of the data anyway (and recompress it). So follow that with:

ops$tkyte%ORA10GR2> alter table t drop unused columns;

Table altered.

and it is gone



Rating

  (33 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

nice one

Zahid, July 31, 2006 - 4:33 am UTC

well demonstration of tricks/tips & techniques.

What is the methodology behinf compression !!

Prashant, July 31, 2006 - 3:10 pm UTC

Hello Tom,

This trick is Superb..Can you please throw some light on Strategy to compress table's data and select data from compressed table, as i know it takes time during insertion...

Thanks


Tom Kyte
July 31, 2006 - 8:46 pm UTC

table compression works when you do direct path operations (insert append, direct path load, alter table move... ) not during normal insert/update/delete.

It works by removing repetitive data and storing it once per block instead of once per occurrence per block.

Column Compression

A reader, July 31, 2006 - 9:24 pm UTC

Tom-
I wish Oracle adds column level compression soon. This would be very useful in Data Warehouse environments where repeated code values (low cardinality columns) can be compressed in the block header.


Tom Kyte
August 01, 2006 - 7:01 am UTC

we have had that since version 9ir2.

It is called a compressed table. Any column, in fact any set of columns, that have repeated values are compressed.

If you have a table with:

first_name
middle_name
last_name
street
city

and you have Allen as a first_name, middle_name, last_name, street, city - either on the same row or across rows - we'll store Allen once.

Adding a column to an existing, populated table

SC, August 21, 2006 - 11:06 am UTC

When adding a column to an existing compressed table that contains data, does the table have to be decompressed as part of the process (either explicitly or under the covers)? This was the case with 9i and so sufficient diskspace had to be provisioined to cater for this? Are there any restrictions to adding a new column? I've read that it is not possible to specify a default value for example.

Tom Kyte
August 27, 2006 - 9:50 am UTC

it depends on the release.

And the data didn't have to be decompressed if you use CREATE TABLE AS SELECT as demonstrated above.

Adding Column in compressed table in Rel 9.2.0.1.0

Sanjay, August 31, 2006 - 3:45 pm UTC

Tom, 

1) Can you show me how can I add column to compressed table ?
2) I was able to add column to the table by exporting it, dropping it, creating table without the compress option, importing the data and adding a column. Is this the correct option. 

NB: The table in question is a huge table. 

>>Except of the sql session, I cannot add column to a compressed table. 

SQL*Plus: Release 9.2.0.1.0 - Production on Thu Aug 31 15:39:09 2006

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.


Connected to:
Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.1.0 - Production

SQL> create table My$table as select * from all_objects
  2  /

Table created.

SQL> alter table  my$table compress ;

Table altered.

SQL> alter table my$table add col1 varchar2(20) ;
alter table my$table add col1 varchar2(20)
                         *
ERROR at line 1:
ORA-22856: cannot add columns to object tables

SQL> alter table my$table nocompress ;

Table altered.

SQL> alter table my$table add col1 varchar2(20) ;
alter table my$table add col1 varchar2(20)
                         *
ERROR at line 1:
ORA-22856: cannot add columns to object tables

SQL>

Thanks, 
Sanjay
boston,MA
 

Tom Kyte
August 31, 2006 - 7:06 pm UTC

you can:

create table new_table COMPRESSED
as
select t.*, <new column here> from old_table t;

drop old_table;
rename new_table to old_table;


that'll be about it in 9i, or upgrade to 10g - you are already 6 patchsets off of supported software as it is...

very veru helpful

Charit, October 13, 2006 - 10:37 am UTC

good work mate...

its very helpful for me

Sravan, December 12, 2006 - 9:16 am UTC

I searched in google and found the link to this website.. i was happy to see this link, I got confidence that my problem got resolved. Thanks a lot for providing needy information with examples.

Datatype

A reader, January 05, 2007 - 3:43 pm UTC

create table new_table COMPRESSED
as 
select t.*, <new column here> from old_table t;


How can the datatype and size of the new column(s) be specified using this technique?

Thanks
Tom Kyte
January 06, 2007 - 8:58 am UTC

ops$tkyte%ORA9IR2> create table t1 as select * from all_users;

Table created.

ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> create table t2
  2  compress
  3  as
  4  select cast(username as varchar2(40)) username,
  5         cast(user_id  as number(10,2)) user_id,
  6             created
  7    from t1
  8  /

Table created.

ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> desc t1
 Name                                     Null?    Type
 ---------------------------------------- -------- ----------------------------
 USERNAME                                 NOT NULL VARCHAR2(30)
 USER_ID                                  NOT NULL NUMBER
 CREATED                                  NOT NULL DATE

ops$tkyte%ORA9IR2> desc t2
 Name                                     Null?    Type
 ---------------------------------------- -------- ----------------------------
 USERNAME                                          VARCHAR2(40)
 USER_ID                                           NUMBER(10,2)
 CREATED                                  NOT NULL DATE


Datatype

A reader, January 06, 2007 - 2:14 pm UTC

Not quite. We need to add columns to a compressed table T. Similar to doing ALTER TABLE T add (new_col varchar2(10))

The ALTER TABLE is not supported in 9iR2 so you suggested doing a CTAS and including the new columns to it.

If I do
create table t2 compress as 
select t.*,'xxx' new_col from t;


I get new_col as CHAR(3) and not VARCHAR2(3) and also it contains that dummy data xxx that I don't really need.

What I really need is a CTAS where I can specify EMPTY columns with the datatype/size I need, just as if I were doing a ALTER TABLE ADD COLUMN

Help? Thanks
Tom Kyte
January 07, 2007 - 8:05 pm UTC

same answer - use cast????


ops$tkyte%ORA9IR2> create table t2
  2  compress
  3  as
  4  select cast(username as varchar2(40)) username,
  5         cast(user_id  as number(10,2)) user_id,
  6             created,
  7             cast( null as char(3) ) new_column ,
  8             cast( null as varchar2(3) ) new_column2
  9    from t1
 10  /

Table created.

Elapsed: 00:00:00.05
ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> desc t1
 Name                                     Null?    Type
 ---------------------------------------- -------- ----------------------------
 USERNAME                                 NOT NULL VARCHAR2(30)
 USER_ID                                  NOT NULL NUMBER
 CREATED                                  NOT NULL DATE

ops$tkyte%ORA9IR2> desc t2
 Name                                     Null?    Type
 ---------------------------------------- -------- ----------------------------
 USERNAME                                          VARCHAR2(40)
 USER_ID                                           NUMBER(10,2)
 CREATED                                  NOT NULL DATE
 NEW_COLUMN                                        CHAR(3)
 NEW_COLUMN2                                       VARCHAR2(3)



and of course, you can always:

a) create table using just "create table ( .... ) compress"

b) then - insert /*+ append */ into


to load it.

Is the index reusable?

kpanchan, February 03, 2007 - 10:25 pm UTC

Tom
Your solution to add column solution very useful for my requirement.

I need to add column to Oracle9i.

If I am follow your solution, When I rename T2 as T1, I will be loosing my indexes.

Is that right? If yes, Can I save Indexes on T1 and create those indexes on T2 later.

I want to retain same indexes on T2 table also.

Tom Kyte
February 04, 2007 - 8:41 am UTC

you would add any indexes to you wanted - you would not "lose" any - indexes stay with a table, if you want T2 to have some indexes, just create them

Cast with union all

Robert Koltai, February 05, 2007 - 6:03 am UTC

Hello Tom,

I wanted to use cast as you suggested in CTAS with union all.
I need number (38) column, but I get number.

This is what I do:

** OK **
create table testOK as
select cast (1 as number(38)) c from dual;
desc testOK;

SQL>
C NUMBER(38)

** NOT OK **
create table testNOTOK as (
select cast (1 as number(38)) c from dual
union all
select cast (2 as number(38)) c from dual
);
desc testNOTOK;

SQL>
C NUMBER

So why does union all "conflict" with the cast?
I did not find the reason in any documentation.

Thanks,
Rob

Tom Kyte
February 05, 2007 - 9:39 am UTC

it doesn't really - you just need to use cast at the top level

ops$tkyte%ORA9IR2> create table testNOTOK as
  2  select cast(c as number(38)) c
  3    from ( select cast (1 as number(38)) c from dual
  4            union all
  5           select cast (2 as number(38)) c from dual
  6         )
  7  /

Table created.

ops$tkyte%ORA9IR2> desc testNOTOK;
 Name                                     Null?    Type
 ---------------------------------------- -------- ----------------------------
 C                                                 NUMBER(38)


Can add to Partition table?

kpanchan, February 05, 2007 - 10:09 am UTC

Tom

Using CAST, can I able to add new column to COMPRESSED PARTITIONED table?

From your solution, We can add new column to COMPRESSED table.

Table T1 is Partitioned and Compressed.

Tried to create table T2 with CAST as given below.

CREATE TABLE T2 as SELECT t1.*, CAST(null as VARCHAR2(10)) C1 FROM t1;

Table T2 was created, but it was not partitioned.

Is it possible to copy partition details to T2 from T1?

Thanks for your reply.


Tom Kyte
February 05, 2007 - 10:38 am UTC

you would have to explicitly put that into the create table as select - the partition details.


ops$tkyte%ORA10GR2> create table t1
  2  PARTITION BY RANGE (dt)
  3  (
  4    PARTITION part1 VALUES LESS THAN (to_date('13-mar-2003','dd-mon-yyyy')) ,
  5    PARTITION part2 VALUES LESS THAN (to_date('14-mar-2003','dd-mon-yyyy')) ,
  6    PARTITION junk VALUES LESS THAN (MAXVALUE)
  7  )
  8  COMPRESS
  9  as
 10  select * from t;

Table created.

Thanks!!!

kpanchan, February 05, 2007 - 1:12 pm UTC

Tom
Thanks very much for your quick response.

Adding a column to a table

Sourabh, August 28, 2007 - 8:45 am UTC

Hi Tom,

I have a scenario where i need to add a column to a fact table which has more than 2000 million records.

I performed a small calculation for 1 million records.

Records : 1000000
Time taken : 70 seconds

If i have to perform on 2000 million records
Records : 2000 * 1000000
Time taken : 2000 * 70 => 140000 sec => 2333 minutes => 38 hours

What according to you would be the fastest method to do it?

Regards
Tom Kyte
September 04, 2007 - 1:38 pm UTC

big_table%ORA10GR2> select count(*) from big_table;

  COUNT(*)
----------
  25000000

big_table%ORA10GR2> set timing on
big_table%ORA10GR2> alter table big_table add x number;

Table altered.

Elapsed: 00:00:00.06
big_table%ORA10GR2>


it should be instantaneous - if not, you must be using a "default" value in which case you can:

a) add column without default
b) alter table t modify newcol default <value>; -- for new inserts
c) update it where it is null (this will still permit concurrent inserts into the table, but of course - the update will prevent updates and deletes to the existing rows)
d) commit;


Alexander, April 24, 2008 - 4:38 am UTC

Hi, Tom!

I tried to follow your steps, but I've got this error:

SQL> CREATE TABLE t AS SELECT * FROM all_objects;

Table created.

SQL> SELECT COUNT(1) AS cnt FROM t;

       CNT
----------
     40779

SQL> DROP TABLE t;

Table dropped.

SQL> CREATE TABLE t COMPRESS AS SELECT * FROM all_objects;

Table created.

SQL> SELECT COUNT(1) AS cnt FROM t;

       CNT
----------
     40779

SQL> ALTER TABLE t ADD (v VARCHAR2 (30));

Table altered.

SQL> ALTER TABLE t SET UNUSED (v);

Table altered.

SQL> ALTER TABLE t DROP UNUSED COLUMNS;
ALTER TABLE t DROP UNUSED COLUMNS
*
ERROR at line 1:
ORA-12996: cannot drop system-generated virtual column


SQL> SELECT * FROM v$version WHERE ROWNUM = 1;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - Prod


Could you explain, why this error is raised?

Thank you!
Tom Kyte
April 28, 2008 - 11:21 am UTC

looks like they withdrew that for 10g, but it is in 11g

ops$tkyte%ORA11GR1> CREATE TABLE t COMPRESS AS SELECT * FROM all_users;

Table created.

ops$tkyte%ORA11GR1> ALTER TABLE t ADD (v VARCHAR2 (30));

Table altered.

ops$tkyte%ORA11GR1> ALTER TABLE t SET UNUSED (v);

Table altered.

ops$tkyte%ORA11GR1> ALTER TABLE t DROP unused columns;

Table altered.

ops$tkyte%ORA11GR1> SELECT * FROM v$version WHERE ROWNUM = 1;

BANNER
-------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - Production




it is sort of "not necessary" of course in this case - in fact, I'd say dropping a column from a compressed table probably should be done via 'alter table t move' anyway (in order to, well, compress the data on the block again...)

DROP COLUMN DOES NOT WORK ON TABLE WITH FEW COMPRESSED PARTITIONS AND FEW UNCOMPRESSED

jenith, August 27, 2009 - 9:46 am UTC

Hi Tom

I have scenario where we have table T1 with partition's P1,p2 compressed p3,p4 uncompressed in this case i am able to make column unused but alter table T1 drop unused columns; fail's

*
ERROR at line 1:
ORA-39726: unsupported add/drop column operation on compressed tables


Tom Kyte
August 28, 2009 - 4:51 pm UTC

not until 11g with advanced compression option - this is true, but, if you have a compressed table (save space), dropping a column without a reorg (waste space) seems "not sensible"

just make it unused and if you want to reclaim the space - reorganize those segments, you should probably have just been using set unused from the get go in this case.

A reader, September 16, 2009 - 12:56 am UTC

Tom - in your Followup above;

"table compression works when you do direct path operations (insert append, direct path load, alter
table move... ) not during normal insert/update/delete."....

Does 11g "COMPRESS FOR ALL OPERATIONS" means it's not true?
Tom Kyte
September 16, 2009 - 10:06 am UTC

correct, 11g Release 1 introduced the advanced compression option which permits compression for inserts and updates using conventional path.


so, as with many things, it means "it is not true anymore"

A reader, September 16, 2009 - 11:01 am UTC

Hello tom,

Is there is any performance issue when doing indert/update/delete on compressed table


Thanks


Tom Kyte
September 16, 2009 - 4:43 pm UTC

well, there would be a couple of cases to be considered - lots of them actually

there is direct path compression and conventional path compression.

direct path:
o insert (not direct path insert) will not be affected
o delete will not be
o update might be. If you update compressed data, it'll likely decompress and migrate the row. If you update non-compressed data, no affect

conventional path:

o most inserts will not be impacted, only the insert that takes the block over "pctfree" and would normally take it off the freelist would. Instead of just taking it off freelist, it first compresses the block and if that freed enough space - it just inserts into the block. If that did not free enough space - the block is taken off the freelist. So, everynow and then and insert will "feel the pain"

o deletes should not be affected

o updates - see insert in this section. If the update would cause the block to exceed pctfree and be removed from the freelist, the compression is done first.




In general, compression negatively impacts loading - in the hopes of reducing storage needs and improving the speed of retrieval.

Useful Tips

Prasanna, September 30, 2009 - 2:14 am UTC

Thanks a lot

How compressed is a 'compressed' table?

Mike, November 09, 2009 - 2:55 pm UTC

> If you update compressed data, it'll likely decompress and migrate the row.

Is there any way to determine what % of blocks are actually compressed, in a table or partition that has compression enabled?

(short of forcibly moving it and seeing a change in the space used)
Tom Kyte
November 11, 2009 - 2:40 pm UTC

no, there is not.

well, not truly, you could do something like using dbms_rowid.rowid_block_number to get an ESTIMATE of the number of rows/block and then bin them up in some ranges to get an idea of how many blocks have 0..100 rows, 101..200 and so on.

The ones with "high rows/block" would likely be compressed data blocks

Not 100% accurate by any means, but a good guess.


In 11gr2 - there is a tool to analyze a table and estimate how well it would compress, that is new.



just to clarify

Jiri, November 14, 2009 - 3:36 pm UTC

reader asked "I wish Oracle adds column level compression soon. This would be very useful in Data Warehouse
environments where repeated code values (low cardinality columns) can be compressed in the block
header."

tom responded "we have had that since version 9ir2. It is called a compressed table. Any column, in fact any set of columns, that have repeated values are compressed."


I'm not sure if reader asked for this, but I don't think Oracle does true column level compression. Correct me if I'm wrong, my understanding is that Oracle does block compression only. Other systems like Teradata allow true column level compression (compression of a single column or even specific set of values in a single column) - this decreases compression level but can be faster in insert/delete/update operations.




Tom Kyte
November 15, 2009 - 3:25 pm UTC

actually, I think you are speaking of columnar compression ala sybase IQ, vertica - but not teradata.

oh, and of exadata 2 from Oracle as well.

http://www.google.com/search?hl=en&safe=off&q=hybrid+columnar+compression+site%3Aoracle.com&aq=f&oq=&aqi=


nope

jiri, November 16, 2009 - 9:55 pm UTC

nope, I'm talking about classic relational database compression here


Teradata has column level compression (you can compress individual columns) http://www.teradataforum.com/l020829a.htm


here is sample teradata DDL

CREATE TABLE Properties (
Address VARCHAR(40),
City CHAR(20) COMPRESS (‘Chicago’),
StateCode CHAR(2)
);


Tom Kyte
November 23, 2009 - 12:39 pm UTC

... Customers using Teradata compression in V2R4 have experienced up to 50% capacity savings and scan performance increases up to 35%....

we meet or exceed that with block level compression. We have columnar compression (exadata version 2.0) and block level compression (since 9iR2) - and it meets or exceeds that savings...


... In Teradata V2R4, one value in each column can be compressed out of the row body....

that doesn't seem to generally useful, unless you have a column with one value that is very very very wide and repeats a heck of a lot.

but their statements about block level compression - are not really true. If they were - I'd expect that they'd have numbers somewhere demonstrating them.

come on

Jiri, November 28, 2009 - 10:50 am UTC

With all the respect, you are really not being professional here. I don't want to argue about oracle vs any other database and compare compression methods, but ...

first you said that oracle had column level compression since 9R2, when I corrected it, you said that I really don't know what I'm talking about by saying "actually, I think you are speaking of columnar compression ala sybase IQ, vertica - but not teradata", when I corrected that, you threw comment like this?


Is this really Tom who is responding to these discussions? I'm simply surprised by kinda rude childish responses with no "thank you", no "you are correct", "I am sorry" ... but hey I have no clue what I'm talking about, I'm just OCP, MSDBA, MCSE and Teradata Certified Professional.



Is this enough information about field compression in Teradata? http://www.teradata.com/t/WorkArea/DownloadAsset.aspx?id=1432






Tom Kyte
November 28, 2009 - 4:07 pm UTC

It sounded like you were talking columnar compression to me, especially what the reader wrote - the original poster.

And if you slow down and read what I wrote it is:

we meet or exceed that with block level compression. We have columnar compression (exadata version 2.0) and block level compression (since 9iR2) - and it meets or exceeds that savings...


where did I say "first you said that oracle had column level compression since 9R2,"

And your ordering of the timeline is quite strange.


You say "first you said" - however, I wrote that AFTER you said column compression.

Then you said I said "I don't know what your talking about" - the only way you get that order is if you read the page from the bottom up.


You wrote "column compression - like teradata" (and remember, I know nothing about you, your background, your level of experience with Oracle, teradata, anything - you know about me - I know *nothing* about you. without references (links, context, something) I have to guess many times at what people are referring to and the levels of people that come here range from - well, the entire spectrum is represented)

I wrote "I think it was columnar compression like Sybase IQ, Vertica, and Exadata" (given that this is what the industry has been working on for a while, this is where the real compression comes from )

You wrote "No, this <link to tersdata, which I read>"

And I wrote "Ok, we meet or best those numbers with block compression - it doesn't see to be worth it, we would achieve at least that level with our block compression" and "exadata goes a step further" - so I don't see your point, it doesn't seem to me to have any advantages over what we already had, what we've had for many releases.


Yes, this is Tom



And so what about teradata, I've already said we meet or beat that in ever case? Can you tell us mathematically how this is not true?




True, I misunderstood what you meant when you said column compression - but only because the columnar compression is what really achieves massive compression and the column compression that teradata has there, frankly, doesn't seem to be very impressive.

Maybe I'm missing something, feel free to point it out.

Very Strange - works in 10.2.0.3 as well as 11.1.0.6 but not in 11.1.0.7

Devanshi Parikh, December 09, 2009 - 12:06 pm UTC

ops$tkyte%ORA11GR1> CREATE TABLE t COMPRESS AS SELECT * FROM all_users;

Table created.

ops$tkyte%ORA11GR1> ALTER TABLE t ADD (v VARCHAR2 (30));

Table altered.

ops$tkyte%ORA11GR1> ALTER TABLE t SET UNUSED (v);

Table altered.

ops$tkyte%ORA11GR1> ALTER TABLE t DROP unused columns;

Table altered.

ops$tkyte%ORA11GR1> SELECT * FROM v$version WHERE ROWNUM = 1;

BANNER
-------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - Production


Tried this same sequence on my 11.1.0.7 database. Here are the results.

SQL> drop table t;

Table dropped.

SQL> CREATE TABLE t COMPRESS AS SELECT * FROM all_users;

Table created.

SQL> ALTER TABLE t ADD (v VARCHAR2 (30));

Table altered.

SQL> ALTER TABLE t SET UNUSED (v);

Table altered.SQL> ALTER TABLE t DROP unused columns;
ALTER TABLE t DROP unused columns
*
ERROR at line 1:
ORA-39726: unsupported add/drop column operation on compressed tables

SQL> SELECT * FROM v$version WHERE ROWNUM =1;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production

So, seems like this way of modifying a compressed table is not consistent across 11gR1 releases.



Tom Kyte
December 10, 2009 - 2:32 pm UTC

that is correct, this ability is part of the OLTP table compression - sorry, they fixed it in 11gR1, it would be:

ops$tkyte%ORA11GR1> CREATE TABLE t COMPRESS for all operations AS SELECT * FROM all_users;

Table created.

ops$tkyte%ORA11GR1> ALTER TABLE t ADD (v VARCHAR2 (30));

Table altered.

ops$tkyte%ORA11GR1> ALTER TABLE t SET UNUSED (v);

Table altered.

ops$tkyte%ORA11GR1> ALTER TABLE t DROP unused columns;

Table altered.

ops$tkyte%ORA11GR1> SELECT * FROM v$version WHERE ROWNUM = 1;

BANNER
-------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - Production

ORA-12296

MM, June 08, 2010 - 6:57 am UTC

Tom,
I have a partitioned table and when I try to drop the unused columns I am getting ORA-12996: cannot drop system-generated virtual column. My oracle version 10g Enterprise 10.1.0.2.0
How can the unused column be dropped?

Thanks

Tom Kyte
June 09, 2010 - 8:49 am UTC

give example.

example

MM, June 09, 2010 - 9:12 am UTC

It is the same one as the post on April 24th 2008 above.

sql>select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.1.0.2.0 - Prod
PL/SQL Release 10.1.0.2.0 - Production
CORE 10.1.0.2.0 Production
TNS for 32-bit Windows: Version 10.1.0.2.0 - Production
NLSRTL Version 10.1.0.2.0 - Production

sql>create table my_objs compress as select * from dba_objects;

Table created.

sql>alter table my_objs set unused column status;

Table altered.

sql>alter table my_objs drop unused columns;
alter table my_objs drop unused columns
*
ERROR at line 1:
ORA-12996: cannot drop system-generated virtual column

I am getting the same error in the partitioned table too. Is there any other way to drop the unused column.

Thanks
Tom Kyte
June 10, 2010 - 11:58 am UTC

I would need the step by steps to reproduce that exact error.

A reader, June 10, 2010 - 8:22 am UTC

The reason is that your db is 10g R1.

See the copy from Tom's 1st response 3 years ago.
ops$tkyte%ORA10GR2> alter table t drop column x;
alter table t drop column x
*
ERROR at line 1:
ORA-39726: unsupported add/drop column operation on compressed tables

but make it "disappear"
ops$tkyte%ORA10GR2> alter table t set unused column x;

Table altered.

yes, which if you ask me is OK since you would have to rewrite the entire segment to
truly get rid of the data anyway (and recompress it). So follow that with:

ops$tkyte%ORA10GR2> alter table t drop unused columns;

Table altered.

Example

MM, June 10, 2010 - 1:49 pm UTC

Tom, 
  I have given the script of exactly what I did. I tried the same in release 2. I am having the same issue unable to drop the unused columns. Here it is. 

SQL>select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
PL/SQL Release 10.2.0.3.0 - Production
CORE 10.2.0.3.0 Production
TNS for 64-bit Windows: Version 10.2.0.3.0 - Production
NLSRTL Version 10.2.0.3.0 - Production

SQL>create table my_objs compress as select * from dba_objects;

Table created.

SQL>alter table my_objs set unused column status;

Table altered.

SQL>alter table my_objs drop unused columns;
alter table my_objs drop unused columns
*
ERROR at line 1:
ORA-12996: cannot drop system-generated virtual column

However, I am not able to recreate the issue with a partitioned table! But, I still have the issue with my existing partitioned table.
Interestingly enough, when I tried to create the table first and then insert values (instead of creating and inserting at the same time) I am not getting the issue.
SQL> create table my_ob compress as select * from all_objects where 1=0;

Table created.

SQL>insert into my_ob select * from all_objects;

49286 rows created.

SQL>
SQL>commit;

Commit complete.

SQL>alter table my_ob set unused column status;

Table altered.

SQL>
SQL>alter table my_ob drop unused columns;

Table altered.


I am not sure if there is a solution for this. But,thanks for your time. 

Tom Kyte
June 11, 2010 - 6:52 am UTC

I saw this:

... I am getting the same error in the partitioned table too. ...

and looked at the example and said to myself "hmm, no partitioning - partitioning question - missing information". In other words, the red herring you threw in there confused me.


It is the compress.

ops$tkyte%ORA10GR2> create table t compress as select * from all_objects where rownum=1;

Table created.

ops$tkyte%ORA10GR2> alter table t set unused column status;

Table altered.

ops$tkyte%ORA10GR2> alter table t drop unused columns;
alter table t drop unused columns
*
ERROR at line 1:
ORA-39726: unsupported add/drop column operation on compressed tables



the error is wrong in your older release, but the cause is the same:

$ oerr ora 39726
39726, 00000, "unsupported add/drop column operation on compressed tables"
// *Cause:  An unsupported add/drop column operation for compressed table
//          was attemped.
// *Action: When adding a column, do not specify a default value.
//          DROP column is only supported in the form of SET UNUSED column
//          (meta-data drop column).



Also, if your goal is to COMPRESS, dropping a column doesn't make sense - setting unused is as good as you get.

Since you do not insert and reuse space in a compressed table like that - you don't need to drop the column.

If you want to reclaim the space, you'd have to REORGANIZE the object, just alter table move it.

Error Not consistent

MM, June 11, 2010 - 8:18 am UTC

Tom,
  The error is not consistent. Here is the second example in my previous post, where I create the compressed table and then populate it with data, then I can drop the unused columns without any errors. 

SQL> create table my_ob compress as select * from all_objects where 1=0;

Table created.

SQL>insert into my_ob select * from all_objects;

49286 rows created.

SQL>
SQL>commit;

Commit complete.

SQL>alter table my_ob set unused column status;

Table altered.

SQL>
SQL>alter table my_ob drop unused columns;

Table altered.

 Either I should be able to drop the columns from a compressed table all the time or not drop the columns at all. Bug?!!

Thanks

Tom Kyte
June 22, 2010 - 6:36 am UTC

it is pretty consistent for me.

ops$tkyte%ORA10GR2> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Prod
PL/SQL Release 10.2.0.4.0 - Production
CORE    10.2.0.4.0      Production
TNS for Linux: Version 10.2.0.4.0 - Production
NLSRTL Version 10.2.0.4.0 - Production

ops$tkyte%ORA10GR2> create table my_ob compress as select * from all_objects where 1=0;

Table created.

ops$tkyte%ORA10GR2> insert into my_ob select * from all_objects;

50080 rows created.

ops$tkyte%ORA10GR2> commit;

Commit complete.

ops$tkyte%ORA10GR2> alter table my_ob set unused column status;

Table altered.

ops$tkyte%ORA10GR2> alter table my_ob drop unused columns;
alter table my_ob drop unused columns
*
ERROR at line 1:
ORA-39726: unsupported add/drop column operation on compressed tables


every single time. If you can reproduce your issue, please utilize support.


But again, it doesn't really matter, if you went out of your way to compress a table your goal must be to minimize space - hence you would be doing a full reorganization - not a drop column - in order to repack the compressed data on blocks.

Add column

TB, September 09, 2013 - 12:19 pm UTC

Hi Tom,
There are some restriction when adding a column to a compressed table:

Adding and Dropping Columns in Compressed Tables
The following restrictions apply when adding columns to compressed tables:
■ Basic compression—You cannot specify a default value for an added column.
■ OLTP compression—If a default value is specified for an added column, then the
column must be NOT NULL. Added nullable columns with default values are not
supported.


I use basic compression. Is there any trick you can suggest to add a column with default value (and not null claues for fast update)?
Thanks
Tom Kyte
September 10, 2013 - 9:42 am UTC

you would want to create table new as select ...., 'x' x from old;

alter x to be default 'x'
drop old
rename new


think about it, for basic compression which ONLY works during direct path operations - if we added the column to the compressed table - every row would have to be uncompressed, migrated to a new block, have 'x' added to it, and then stored uncompressed. You'd end up with an uncompressed table with every row migrated and lots of apparently empty blocks where the compressed data used to be.


you just want to do a direct path operation here - create table new as select from old.

question on licence

A reader, February 22, 2017 - 1:55 pm UTC

hi
some of owr database have no "Advanced compression" licence.

so to frop unused column on a table having the compress BASIC,

is it permitted to do :

alter table t compress for all operations;

alter table t drop unused columns;

alter table t compress basic;

?


Connor McDonald
February 23, 2017 - 2:45 am UTC

I'm not sure, but I would not drop unused columns like that anyway (assuming your table is large).

I would do:

create table new_copy compress as select ...

A 'drop unused' is a very expensive operation.

Follow up

A reader, February 23, 2017 - 6:06 am UTC

I've experienced some issues in 11g that exchange partition will fail even when setting unused cols.
Is that still true sometimes and when?
Connor McDonald
February 25, 2017 - 12:26 am UTC

adding the column with Default and non null clause

Rajeshwaran Jeyabal, January 09, 2023 - 8:30 am UTC

When we add a new column with a default value as “literal” it works. But not with “function” calls, why so ?

demo@ATP19C> create table t
  2  COMPRESS
  3  as
  4  select * from all_objects
  5  where rownum <=10;

Table created.

demo@ATP19C> alter table t add X number default 55 not null;

Table altered.

demo@ATP19C> alter table t add Y timestamp default systimestamp not null;
alter table t add Y timestamp default systimestamp not null
                  *
ERROR at line 1:
ORA-39726: unsupported add/drop column operation on compressed tables

Connor McDonald
January 16, 2023 - 3:21 am UTC

I suspect that is a limitation that will be lifted

19c
====
SQL> create table t
  2      COMPRESS
  3      as
  4      select * from all_objects
  5      where rownum <=10;

Table created.

SQL>
SQL> alter table t add X number default 55 not null;

Table altered.

SQL>
SQL> alter table t add Y timestamp default systimestamp not null;
alter table t add Y timestamp default systimestamp not null
                  *
ERROR at line 1:
ORA-39726: unsupported add/drop column operation on compressed tables

21c
=======
SQL> create table t
  2      COMPRESS
  3      as
  4      select * from all_objects
  5      where rownum <=10;

Table created.

SQL>
SQL> alter table t add X number default 55 not null;

Table altered.

SQL>
SQL> alter table t add Y timestamp default systimestamp not null;

Table altered.