How to find the root cause of ORA-54033 error when altering column data type - oracle

I am attempting to alter the data type of a column from a NUMBER to a VARCHAR2 in an existing database table. When running the following ALTER TABLE statement I receive the "ORA-54033: column to be modified is used in a virtual column expression" error:
ALTER TABLE table MODIFY (col1 varchar2(8));
I have already worked through the directions listed here. When looking at the SYS generated export statistics using the following query
select column_name, data_default, hidden_column
from user_tab_cols
where table_name = 'Table';
there is nothing referencing col1 in export statistics. There are about 15 hidden, SYS generated rows associated with the table and they all have a data default value of <Long>. There are no virtual columns in the DDL, nor is this column being used for any indexes or as a FK. I have also had the DBA run the following:
SELECT EXTENSION_NAME, EXTENSION, CREATOR, DROPPABLE
FROM DBA_STAT_EXTENSIONS
WHERE TABLE_NAME='Table'
and the output lines up with what I find in user_tab_cols. Where else can I look for this seemingly buried virtual column?

Related

Apex Oracle How To Create Conditional Column

I am new to using Apex Oracle to create a table and insert values in it. I need to create a column that is only mandatory if the value for another column is "Y" (if it is "N", then it is not mandatory). The type of the other column is a CHAR with length 1. How could I do this? Would this be done in SQL Scripts or SQL Commands? Similarly, is there a way to delete old SQL commands that were used (that now I realize are incorrect)?
Thank you!
Welcome to Oracle APEX and Stack Overflow. You can create objects (tables/views) in both SQL commands and SQL Scripts. For ad hoc creating, SQL Commands is probably easier. To remove (called "drop" in oracle) objects that you create, that can be done in SQL Commands, or even easier in the "Object Browser" - locate the object and select "drop". Note that this cannot be undone.
About the requirement for a column to be conditionally mandatory:
This can be enforced in the database using a check constraint.
CREATE TABLE test_table (
id NUMBER GENERATED AS IDENTITY,
col1 VARCHAR2(1),
col2 VARCHAR2(10));
Table TEST_TABLE created.
ALTER TABLE test_table ADD CONSTRAINT test_table_c1
CHECK ((col1 = 'Y' AND col2 IS NOT NULL) or (col1 != 'Y'));
Table TEST_TABLE altered.
INSERT INTO test_table(col1,col2) VALUES ('N',NULL);
1 row inserted.
INSERT INTO test_table(col1,col2) VALUES ('Y',NULL);
INSERT INTO test_table(col1,col2) VALUES ('Y',NULL)
Error report -
ORA-02290: check constraint (SAMPLEAPPS.TEST_TABLE_C1) violated
INSERT INTO test_table(col1,col2) VALUES ('Y','Some Value');
1 row inserted.

How to change lots table columns datatypes from one to another in oracle

I have a table with a lots of columns with BLOB type and I need to change it to nvarchar2.
So, to change type I can use following script:
alter table AUDIT_LOG
modify
(
column_name type_name,
column_name2 type_name2
-- etc
);
And to get all columns with given datatype I can use the following:
select column_name, 'NVARCHAR2(4000)'
from all_tab_columns
where table_name = 'TAB_NAME' and data_type = 'BLOB';
But how to join this two scripts into one?
You cannot do DML and DDL operation together in same query. You have to use dynamic SQL in a PL/SQL block
Create a variable and generate the whole alter table query in it.
Execute Immidiate
Refer this and I am sure you will be able to add rest of the logic as per your requirement.
http://www.java2s.com/Tutorial/Oracle/0440__PL-SQL-Statements/EXECUTEIMMEDIATEdynamicsqltoaltersession.htm

How to modify data type in Oracle with existing rows in table

How can I change DATA TYPE of a column from number to varchar2 without deleting the table data?
You can't.
You can, however, create a new column with the new data type, migrate the data, drop the old column, and rename the new column. Something like
ALTER TABLE table_name
ADD( new_column_name varchar2(10) );
UPDATE table_name
SET new_column_name = to_char(old_column_name, <<some format>>);
ALTER TABLE table_name
DROP COLUMN old_column_name;
ALTER TABLE table_name
RENAME COLUMN new_column_name TO old_coulumn_name;
If you have code that depends on the position of the column in the table (which you really shouldn't have), you could rename the table and create a view on the table with the original name of the table that exposes the columns in the order your code expects until you can fix that buggy code.
You have to first deal with the existing rows before you modify the column DATA TYPE.
You could do the following steps:
Add the new column with a new name.
Update the new column from old column.
Drop the old column.
Rename the new column with the old column name.
For example,
alter table t add (col_new varchar2(50));
update t set col_new = to_char(col_old);
alter table t drop column col_old cascade constraints;
alter table t rename column col_new to col_old;
Make sure you re-create any required indexes which you had.
You could also try the CTAS approach, i.e. create table as select. But, the above is safe and preferrable.
The most efficient way is probably to do a CREATE TABLE ... AS SELECT
(CTAS)
alter table table_name modify (column_name VARCHAR2(255));
Since we can't change data type of a column with values, the approach that I was followed as below,
Say the column name you want to change type is 'A' and this can be achieved with SQL developer.
First sort table data by other column (ex: datetime).
Next copy the values of column 'A' and paste to excel file.
Delete values of the column 'A' an commit.
Change the data type and commit.
Again sort table data by previously used column (ex: datetime).
Then paste copied data from excel and commit.

How to find out that an Oracle Table Partition is a System Generated Partition?

Am creating an Oracle HASH Table Partitions by using the below query
CREATE TABLE Table1 (
ID NUMBER, NAME VARCHAR2(50))
PARTITION BY HASH (ID)
PARTITIONS 25
STORE IN (Tablespace1);
Which Creates 25 HASH table partitions and also, the Database generates the 25 Unique partition names like SYS_P122, SYS_P123, SYS_P124... and so on for the partitions. Is there a way to find out this Partition lets say SYS_P123 is a system generated Partition name with the help of Oracle Catalog tables.
With the below link
http://docs.oracle.com/cd/B28359_01/server.111/b28320/statviews_2096.htm#REFRN20281
I could find the Oracle Table Partition information, but this catalog table does not have any value to say that the give Table Partition is a system generate or not. Is there any way to find out the given table partition name is system generated ?
Am using Oracle version 10 and 11.
Thanks,
Ravi,
Yes. The generated column in dba_objects gives the information.
Run the following query -
select owner, object_name, subobject_name, generated from all_objects where object_name = 'TABLE1' and object_type = 'TABLE PARTITION';
View the description for the 'generated' column in the following link - http://docs.oracle.com/cd/B28359_01/server.111/b28320/statviews_1145.htm#REFRN20146

Alter table after keyword in Oracle

ALTER TABLE testTable ADD column1 NUMBER(1) DEFAULT 0 NOT NULL AFTER column2;
Why can't I use mySql syntax in Oracle too? The above command works in MySql. Can you give me an equivalent that works?
Error report:
SQL Error: ORA-01735: invalid ALTER TABLE option
01735. 00000 - "invalid ALTER TABLE option"
I am asking if there is any way to use after clause in Oracle command that I provided?
Because SQL is a relational algebra. It doesn't care one bit about "where" columns are located within a table, only that they exist.
To get it to work in Oracle, just get rid of the after clause. The Oracle documentation for alter table is here but it boils down to:
alter table testTable
add ( column1 number(1) default 0 not null )
There is no after clause for the alter table command.
Oracle does not support adding columns in the middle of a table, only adding them to the end. Your database design and app functionality should not depend on the order of columns in the database schema. You can always specify an order in your select statement, after all.
However if for some reason you simply must have a new column in the middle of your table there is a work around.
CREATE TABLE tab1New AS SELECT 0 AS col1, col1 AS col2 FROM tab1;
DROP TABLE tab1 PURGE;
RENAME tan1New to tab1;
Where the SELECT 0 AS col1 is your new column and then you specify other columns as needed from your original table. Put the SELECT 0 AS col1 at the appropriate place in the order you want.
Afterwards you may want to run an alter table statement on the column to make sure it's the data type you desire.
Try this :
ALTER TABLE testTable ADD column1 NUMBER(1) DEFAULT 0 NOT NULL

Resources