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.
Related
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?
I have a specific scenario where i have to insert two new columns in an existing table in Oracle. I can not do the dropping and recreating the table. So can it be achieved by any means??
Amit-
I don't believe you can add a column anywhere but at the end of the table once the table is created. One solution might be to try this:
CREATE TABLE MY_TEMP_TABLE AS
SELECT *
FROM TABLE_TO_CHANGE;
Drop the table you want to add columns to:
DROP TABLE TABLE_TO_CHANGE;
It's at the point you could rebuild the existing table from scratch adding in the columns where you wish.
Let's assume for this exercise you want to add the columns named "COL2 and COL3".
Now insert the data back into the new table:
INSERT INTO TABLE_TO_CHANGE (COL1, COL2, COL3, COL4)
SELECT COL1, 'Foo', 'Bar', COL4
FROM MY_TEMP_TABLE;
When the data is inserted into your "new-old" table, you can drop the temp table.
DROP TABLE MY_TEMP_TABLE;
This is often what I do when I want to add columns in a specific location. Obviously if this is a production on-line system, then it's probably not practical, but just one potential idea.
-CJ
In 12c you can make use of the fact that columns which are set from invisible to visible are displayed as the last column of the table:
Tips and Tricks: Invisible Columns in Oracle Database 12c
Maybe that is the 'trick' #jeffrey-kemp was talking about in his comment, but the link there does not work anymore.
Example:
ALTER TABLE my_tab ADD (col_3 NUMBER(10));
ALTER TABLE my_tab MODIFY (
col_1 invisible,
col_2 invisible
);
ALTER TABLE my_tab MODIFY (
col_1 visible,
col_2 visible
);
Now col_3 would be displayed first in a SELECT * FROM my_tab statement.
Note: This does not change the physical order of the columns on disk, but in most cases that is not what you want to do anyway. If you really want to change the physical order, you can use the DBMS_REDEFINITION package.
Although this is somewhat old I would like to add a slightly improved version that really changes column order. Here are the steps (assuming we have a table TAB1 with columns COL1, COL2, COL3):
Add new column to table TAB1:
alter table TAB1 add (NEW_COL number);
"Copy" table to temp name while changing the column order AND rename the new column:
create table tempTAB1 as select NEW_COL as COL0, COL1, COL2, COL3 from TAB1;
drop existing table:
drop table TAB1;
rename temp tablename to just dropped tablename:
rename tempTAB1 to TAB1;
You (still) can not choose the position of the column using ALTER TABLE: it can only be added to the end of the table. You can obviously select the columns in any order you want, so unless you are using SELECT * FROM column order shouldn't be a big deal.
If you really must have them in a particular order and you can't drop and recreate the table, then you might be able to drop and recreate columns instead:-
First copy the table
CREATE TABLE my_tab_temp AS SELECT * FROM my_tab;
Then drop columns that you want to be after the column you will insert
ALTER TABLE my_tab DROP COLUMN three;
Now add the new column (two in this example) and the ones you removed.
ALTER TABLE my_tab ADD (two NUMBER(2), three NUMBER(10));
Lastly add back the data for the re-created columns
UPDATE my_tab SET my_tab.three = (SELECT my_tab_temp.three FROM my_tab_temp WHERE my_tab.one = my_tab_temp.one);
Obviously your update will most likely be more complex and you'll have to handle indexes and constraints and won't be able to use this in some cases (LOB columns etc). Plus this is a pretty hideous way to do this - but the table will always exist and you'll end up with the columns in a order you want. But does column order really matter that much?
I am trying to insert rows in a ErrorTable which has a few fields plus an idError which is supossed to be the primary key. I need idError to be autoincremented. However one requirement is we cannot use a trigger, so using O.AutoInc would not work for us.
We also tried to use plain sql using a sequence. However we have two blob fields which makes the query too long ( getting the string literal too long error).
Any idea about how to attack this problem? I am also considering to use UUID.
Note: we are using oracle-xe-11g
In 11g you can have only implement an auto-incrementing identifier with a trigger. So it seems your requirements rule out anything except SYS_GUID. Find out more.
" it also represents another query to get that value "
Not necessarily. If you have the option to define the target table you can set a default values for the UUID column like this:
create table t23 (
id raw(16) default sys_guid() not null primary key
, col1 varchar2(10)
);
Then
SQL> insert into t23 (col1) values ('ABC');
1 row created.
SQL> select * from t23;
ID COL1
-------------------------------- -----------
7DD7216E731C126537615FE1244B4B50 ABC
SQL>
Note: tested on 12C but should work in earlier versions.
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
I am trying to add a CLOB column to a table (change a VARCHAR to a CLOB actually, but it only seems possible by adding a new column, copying and dropping the old). The column should be NOT NULL without a default value (and the table is not empty). How can I achieve this?
My original idea was to create the column with a dummy default, and change that later, but that does not seem possible:
ALTER TABLE foo RENAME COLUMN text TO text_temp;
ALTER TABLE foo ADD (
text CLOB DEFAULT '*' NOT NULL
);
UPDATE foo SET text = text_temp;
ALTER TABLE foo DROP COLUMN text_temp;
ALTER TABLE foo MODIFY (
text CLOB NOT NULL
);
-- ORA-22296: invalid ALTER TABLE option for conversion of LONG datatype to LOB
I also tried defining the column as text CLOB and adding the NOT NULL constraint later, but it gave the same error. Is there a way of doing this, short of recreating the whole table?
Does
ALTER TABLE foo MODIFY text DEFAULT NULL;
work for you?
When adding or removing a default value or a NOT NULL constraint, you don't need to specify the datatype of the column.
EDIT: To quote the Oracle documentation on ALTER TABLE:
If a column has a default value, then you can use the DEFAULT clause to change the default to NULL, but you cannot remove the default value completely. If a column has ever had a default value assigned to it, then the DATA_DEFAULT column of the USER_TAB_COLUMNS data dictionary view will always display either a default value or NULL.
This should explain why you're seeing a difference in SQL Developer.
However, I don't believe there's a significant difference between specifying DEFAULT NULL for a column and not specifying a default value. In both cases, a null value will be assumed for any column not explicitly given a value in an INSERT statement.
You are declaring the column as NOT NULL when you added it to the table, so you don't need to make it NOT NULL again. I think if you corrected the syntax in the final MODIFY clause you would still get an error, albeit a different one (precise number eludes me right now).
But what you are trying to acheive is definitely possible, with the right syntax :)
SQL> alter table t23 add ctxt clob
2 /
Table altered.
SQL> update t23 set ctxt = txt
2 /
2 rows updated.
SQL> alter table t23 modify ctxt not null
2 /
Table altered.
SQL> alter table t23 drop column txt
2 /
Table altered.
SQL> alter table t23 rename column ctxt to txt
2 /
Table altered.
SQL>