Column alias on table declaration - sql

Is there a way, in Oracle 11gR2 that I could create a single column with two names?
Reason I need this is back compatibility, on situations in which this would work:
create table test1 (col1 varchar2(10), col2 [some ref to col1]);
insert into test1 values ('test_value');
and then
SQL> select col1 from test1;
test_value
SQL> select col2 from test1;
test_value
There seem to be a way of thing so on SQL Server, I am looking for the Oracle equivalent to it.
ideas?

You can create a VIRTUAL COLUMN:
CREATE TABLE test1 (
col1 VARCHAR2(10),
col2 VARCHAR2(10) GENERATED ALWAYS AS (col1 || '')
);
INSERT INTO test1 (col1) VALUES ('test_value');
COMMIT;
SELECT * FROM test1;
COL1 COL2
---------- ----------
test_value test_value
However, virtual columns cannot be manipulated by DML. Read more here: Oracle Base - Virtual Columns

Related

oracle sql - How to I escape the result text

If I have the following;
SQL> create table test (field1 varchar(25));
Table created.
SQL> insert into test values ('Ric''s test');
1 row created.
SQL> select * from test;
FIELD1
-------------------------
Ric's test
How can I change the select statement so that the result is,
Ric''s test
so the ' is escaped
Long version, I am writing a statement that will extract the table into sql statements, for example;
create table test2 (field1 varchar(25),
field2 varchar(25),
field3 varchar(25),
field4 varchar(25),
field5 varchar(25)
);
insert into test2 values ('one','two','three''s','four','five');
select 'INSERT INTO othertable (
field1,field2,field3,field4,field5) values
('''||field1||''', '''||field2||''', '''||field3||''',
'''||field4||''', '''||field5||''');' as val from test2;
The result of the last select is;
INSERT INTO othertable (
field1,field2,field3,field4,field5) values
('one', 'two', 'three's',
'four', 'five');
which is redirected into a .sql file, which can then be run later.
However, as you can see the 'three's' is incorrect, and i need to escape it.
Any suggestions really appreciated.
select replace(field1, '''', '''''') from test
You can use the Q quote syntax:
SQL> insert into test values (q'[Ric''s test]');
1 row created.
SQL> select * from test;
FIELD1
-------------------------
Ric''s test
This wil say to Oracle to interpret the string exactly as is; I used [], but you can use quite anything you want: [], {}, <>, ...

Alter table to modify default value of column

I have a requirement where we need to modify a column's default value in database table. The table is already an existing table in database and currently the default value of the column is NULL.
Now if add a new default value to this column, If I am correct it updates all the existing NULLs of the column to new DEfault value. Is there a way to not to do this but still set a new default value on column.
I mean I do not want the existing NULLs to be updated and want them to remain as NULLs.
Any help on this is appreciated.
Thanks
Your belief about what will happen is not correct. Setting a default value for a column will not affect the existing data in the table.
I create a table with a column col2 that has no default value
SQL> create table foo(
2 col1 number primary key,
3 col2 varchar2(10)
4 );
Table created.
SQL> insert into foo( col1 ) values (1);
1 row created.
SQL> insert into foo( col1 ) values (2);
1 row created.
SQL> insert into foo( col1 ) values (3);
1 row created.
SQL> select * from foo;
COL1 COL2
---------- ----------
1
2
3
If I then alter the table to set a default value, nothing about the existing rows will change
SQL> alter table foo
2 modify( col2 varchar2(10) default 'foo' );
Table altered.
SQL> select * from foo;
COL1 COL2
---------- ----------
1
2
3
SQL> insert into foo( col1 ) values (4);
1 row created.
SQL> select * from foo;
COL1 COL2
---------- ----------
1
2
3
4 foo
Even if I subsequently change the default again, there will still be no change to the existing rows
SQL> alter table foo
2 modify( col2 varchar2(10) default 'bar' );
Table altered.
SQL> select * from foo;
COL1 COL2
---------- ----------
1
2
3
4 foo
SQL> insert into foo( col1 ) values (5);
1 row created.
SQL> select * from foo;
COL1 COL2
---------- ----------
1
2
3
4 foo
5 bar
ALTER TABLE *table_name*
MODIFY *column_name* DEFAULT *value*;
worked in Oracle
e.g:
ALTER TABLE MY_TABLE
MODIFY MY_COLUMN DEFAULT 1;
ALTER TABLE {TABLE NAME}
ALTER COLUMN {COLUMN NAME} SET DEFAULT '{DEFAULT VALUES}'
example :
ALTER TABLE RESULT
ALTER COLUMN STATUS SET DEFAULT 'FAIL'
Following Justin's example, the command below works in Postgres:
alter table foo alter column col2 set default 'bar';
ALTER TABLE <table_name> MODIFY <column_name> DEFAULT <defult_value>
EX: ALTER TABLE AAA MODIFY ID DEFAULT AAA_SEQUENCE.nextval
Tested on Oracle Database 12c Enterprise Edition Release 12.2.0.1.0
For Sql Azure the following query works :
ALTER TABLE [TableName] ADD DEFAULT 'DefaultValue' FOR ColumnName
GO

Exchange column order of table after it is created

I have created a table with 4 columns. I need to change the structure of the table. I need to interchange the position of the 4th and 2nd columns permanently. Is this possible in Oracle?
Not possible. See this.
Oracle only allows columns to be added to the end of an existing
table.
So you must drop and recreate the tables.
You can run a script like this:
CREATE TABLE TMP_TBL as SELECT * FROM TBL_ORIG;
ALTER TABLE TBL_ORIG ADD COLUMN COL3;
DROP TABLE TBL_ORIG;
CREATE TABLE TBL_ORIG AS SELECT COL1, COL3, COL2 FROM TMP_TBL;
DROP TABLE TMP_TBL
You would need to consider indexes as well as storage concerns.
Why in the world is this necessary? Column order means nothing in SQL.
Swap of columns col1 and col2
It is assumed that col1 is int and col2 is varchar2(20)
-- drop all indexes and constraints concerning col1 and col2
alter table your_table add temp_col int; -- type of col1
update your_table set col1 = null, temp_col = col1;
alter table your_table modify col1 varchar2(20); -- type of col2
update your_table set col2 = null, col1 = col2;
alter table your_table modify col2 int; -- type of col1
update your_table set col2 = temp_col;
alter table your_table drop column temp_col;
alter table your_table rename column col1 to temp_col;
alter table your_table rename column col2 to col1;
alter table your_table rename column temp_col to col1;
-- recreate indexes and constraints
Simply rename table columns if they are the same datatype. If not then Alter - see Sean and Egor examples.
Rename:
http://docs.oracle.com/cd/E11882_01/server.112/e25494/tables006.htm#ADMIN11662
And on the interview they are looking for Sean's answer. Just FYI...

Inserting into too many columns via SELECT query

While this works as expected:
SQL> DROP TABLE TEST1;
Table dropped.
SQL> CREATE TABLE TEST1 (COL1 INTEGER, COL2 INTEGER);
Table created.
SQL> INSERT WHEN 1=1
2 THEN INTO TEST1 (COL1, COL2)
3 SELECT 1, 0 FROM DUAL;
1 row created.
SQL>
I receive a strange "ORA-00918: column ambiguously defined" error attempting this with more than two columns:
SQL> DROP TABLE TEST1;
Table dropped.
SQL> CREATE TABLE TEST1(COL1 INTEGER, COL2 INTEGER, COL3 INTEGER);
Table created.
SQL> INSERT WHEN 1=1
2 THEN INTO TEST1 (COL1, COL2, COL3)
3 SELECT 1, 0, 0 FROM DUAL;
THEN INTO TEST1 (COL1, COL2, COL3)
*
ERROR at line 2:
ORA-00918: column ambiguously defined
SQL>
Why am I receiving ORA-00918 errors here? Is there a limit on how many columns I can SELECT in an INSERT WHEN ... THEN INTO ... SELECT pattern?
Note: I'm using Oracle 11.2.0.1.0, and the actual query I'm attempting to execute in production is more complex and references other tables (and using "VALUES" would not suffice). This is just the simplified case...
Use aliases :
SQL> CREATE TABLE TEST1(COL1 INTEGER, COL2 INTEGER, COL3 INTEGER);
Table created.
SQL> INSERT WHEN 1=1
2 THEN INTO TEST1 (COL1, COL2, COL3)
3 SELECT 1 "1", 0 "2", 0 "3" FROM DUAL;
1 row created.
The reason you get this ambiguous column error is because when you don't provide an alias, Oracle will use a set of rules to name each column. In this case the second and third columns have the same name ("0") and thus can not be referenced unambiguously by the outer query:
SQL> SELECT 1, 0, 0 FROM DUAL;
1 0 0
---------- ---------- ----------
1 0 0
Oracle doesn't look at the data values when performing semantic analysis.
I don't have oracle with me, but it appears that it's the inline query (SELECT FROM DUAL) that's the issue. I recommend aliasing all the fields in that inline query and trying again.
INSERT WHEN 1=1
THEN INTO TEST1 (COL1, COL2, COL3)
SELECT 1 AS c1, 0 AS c2, 0 AS c3 FROM DUAL;
What happens you use use this?
INSERT WHEN 1=1
THEN INTO TEST1 (COL1, COL2, COL3)
SELECT 1 as col1, 0 as col2, 0 as col3 FROM DUAL;

Update with after insert trigger on same table

I have a to write a insert trigger on a tableA. which will perform update with same table but different column. I am getting error while doing this. My trigger is
create or replace trigger trigger_A
after insert on table_A
begin
update table_A set col1=1 where col1 is null;
end;
I have an application will perform col2 alone will be inserted and col1 will be kept null. so my trigger will give value for col1 once the row is inserted. But i am getting error saying "Trigger is failed and invalid" when a row is inserted.
How to do this. TIA.
If you want to assign a simple default value, the easiest way is to declare it on the table, using the DEFAULT clause.
SQL> create table t42
2 ( col1 number default 1 not null
3 , col2 date)
4 /
Table created.
SQL> insert into t42 (col2) values (sysdate)
2 /
1 row created.
SQL> select * from t42
2 /
COL1 COL2
---------- ---------
1 03-AUG-11
SQL>
This works with literals or pseudocolumns such as SYSDATE or USER. If you want to derive a more complicated value with a user-defined function or a sequence, you will need to use
a trigger.
Here is a new version of the table...
SQL> create table t42
2 ( col1 number default 1 not null
3 , col2 date default sysdate
4 , col3 varchar2(30) default user
5 , col4 number )
6 /
Table created.
SQL>
... with a trigger:
SQL> create or replace trigger t42_trg
2 before insert or update
3 on t42
4 for each row
5 begin
6 if :new.col4 is null
7 then
8 :new.col4 := my_seq.nextval;
9 end if;
10 end;
11 /
Trigger created.
SQL> insert into t42 (col1, col2, col3)
2 values (99, sysdate, 'MR KNOX')
3 /
1 row created.
SQL> select * from t42
2 /
COL1 COL2 COL3 COL4
---------- --------- ------------------------------ ----------
99 03-AUG-11 MR KNOX 161
SQL>
Note that although every column on the table is defaultable, I have to populate at least one column to make the SQL valid:
SQL> insert into t42 values ()
2 /
insert into t42 values ()
*
ERROR at line 1:
ORA-00936: missing expression
SQL>
But I can pass in NULL to COL4 to get a completely defaulted record:
SQL> insert into t42 (col4) values (null)
2 /
1 row created.
SQL> select * from t42
2 /
COL1 COL2 COL3 COL4
---------- --------- ------------------------------ ----------
99 03-AUG-11 MR KNOX 161
1 03-AUG-11 APC 162
SQL>
Caveat lector: my trigger uses the new 11g syntax. In previous versions we have to assign the sequence value using a SELECT statement:
select my_seq.nextval
into :new.col4
from dual;
You cannot update a table where the trigger is invoked:
Within a stored function or trigger, it is not permitted to modify a
table that is already being used (for reading or writing) by the
statement that invoked the function or trigger.
Doing so will generate Error 1442:
Error Code: 1442
Can't update table 'MyTable' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
In short, we are not allowed to update the table in use - but your case is simple, only want to update the field if it's NULL, for this choose BEFORE INSERT ON trigger, this way you can update all the fields of the new/current entry/row (as it has not been entered yet):
DELIMITER //
DROP TRIGGER IF EXISTS trigger_A//
CREATE TRIGGER trigger_A BEFORE INSERT ON table_A
FOR EACH ROW BEGIN
IF NEW.col1 IS NULL THEN
set NEW.col1 = <some-value>;
ENF IF;
END;
//
DELIMITER ;