How to compare two Oracle schemas to get delta changes by Altering the table not to drop and recreate it - oracle

I've already tried out a tool named TOYS. I found it free but unfortunately it didn't work.
Then, I tried "RED-Gate Schema Compare for Oracle" but it uses the technique to drop and recreate the table mean while I need to just alter the table with the newly added/dropped columns.
Any help is highly appreciated
Thanks

Starting from Oracle 11g you could use dbms_metadata_diff package and specifically compare_alter() function to compare metadata of two schema objects:
Schema #1 HR
create table tb_test(
col number
)
Schema #2 HR2
create table tb_test(
col_1 number
)
select dbms_metadata_diff.compare_alter( 'TABLE' -- schema object type
, 'TB_TEST' -- object name
, 'TB_TEST' -- object name
, 'HR' -- by default current schema
, 'HR2'
) as res
from dual;
Result:
RES
-------------------------------------------------
ALTER TABLE "HR"."TB_TEST" ADD ("COL_1" NUMBER);
ALTER TABLE "HR"."TB_TEST" DROP ("COL");

Related

Creation of Oracle temporary table with same table structure to that of a existing table

How to create a global temporary table with same table structure to that of a existing table?
I know this concept is available in SQL server like "select * into #temp123 from abc". But I want to perform the same in Oracle.
Create global temporary table mytemp
as
select * from myTable
where 1=2
Global temporary tables in Oracle are very different from temporary tables in SQL Server. They are permanent data structures, it is merely the data in them which is temporary (limited to the session or transaction, depending on how a table is defined).
Therefore, the correct way to use global temporary tables is very different to how we use temporary tables in SQL Server. The CREATE GLOBAL TEMPORARY TABLE statement is a one-off exercise (like any other table). Dropping and recreating tables on the fly is bad practice in Oracle, which doesn't stop people wanting to do it.
Given the creation of a global temporary table should a one-off exercise, there is no real benefit to using the CREATE TABLE ... AS SELECT syntax. The statement should be explicitly defined and the script stored in source control like any other DDL.
You have tagged your question [oracle18c]. If you are really using Oracle 18c you have a new feature open to you, private temporary tables, which are closer to SQL Server temporary tables. These are tables which are genuinely in-memory and are dropped automatically at the end of the transaction or session (again according to definition). These are covered in the Oracle documentation but here are the headlines.
Creating a private temporary table data with a subset of data from permanent table T23:
create table t23 (
id number primary key
, txt varchar2(24)
);
insert into t23
select 10, 'BLAH' from dual union all
select 20, 'MEH' from dual union all
select 140, 'HO HUM' from dual
/
create private temporary table ORA$PTT_t23
on commit preserve definition
as
select * from t23
where id > 100;
The ORA$PTT prefix is mandatory (although it can be changed by setting the init.ora parameter PRIVATE_TEMP_TABLE_PREFIX, but why bother?
There after we can execute any regular DML on the table:
select * from ORA$PTT_t23;
The big limitation is that we cannot use the table in static PL/SQL. The table doesn't exist in the data dictionary as such, and so the PL/SQL compiler hurls - even for anonymous blocks:
declare
rec t23%rowtype;
begin
select *
into rec
from ORA$PTT_t23';
dbms_output.put_line('id = ' || rec.id);
end;
/
ORA-06550: line 6, column 10: PL/SQL: ORA-00942: table or view does not exist
Any reference to a private temporary table in PL/SQL must be done with dynamic SQL:
declare
n pls_integer;
begin
execute immediate 'select id from ORA$PTT_t23' into n;
dbms_output.put_line('id = ' || n);
end;
/
Basically this restricts their usage to SQL*Plus (or sqlcl scripts which run a series of pure SQL statements. So, if you have a use case which fits that, then you should check out private temporary tables. However, please consider that Oracle is different from SQL Server in many aspects, not least its multi-version consistency model: readers do not block writers. Consequently, there is much less need for temporary tables in Oracle.
In the SQL Server's syntax the prefix "#" (hash) in the table name #temp123 means - create temporary table that is only accessible via the current session ("##" means "Global").
To achive exactly the same thing in Oracle you can use private temporary tables:
SQL> show parameter private_temp_table
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
private_temp_table_prefix string ORA$PTT_
create table mytab as
select 1 id, cast ('aaa' as varchar2 (32)) name from dual
;
create private temporary table ora$ptt_mytab on commit preserve definition as
select * from mytab where 1=0
;
Private TEMPORARY created.
Afterwards you can use these tables in SQL and PL/SQL blocks:
declare
r mytab%rowtype;
begin
insert into ora$ptt_mytab values (2, 'bbb');
select id + 1, name||'x' into r from ora$ptt_mytab where rownum = 1;
insert into ora$ptt_mytab values r;
end;
/
select * from mytab
union all
select * from ora$ptt_mytab;
ID NAME
---------- --------------------------------
1 aaa
2 bbb
3 bbbx
Some important restrictions on private temporary tables:
The name must always be prefixed with whatever is defined with the parameter PRIVATE_TEMP_TABLE_PREFIX. The default is ORA$PTT_.
You cannot reference PTT in the static statements of the named PL/SQL blocks, e.g. packages, functions, or triggers.
The %ROWTYPE attribute is not applicable to that table type.
You cannot define column with default values.

Update of two same tables on different oracle schemas using primary key

I am scratching our head to resolve the issue with good performance, we managed to find out the solution in java by using hash map, but as the table contains 1L records its pretty tough to manage this part.
I am looking for the best possible option.
I have two schemas on same oracle database. I need to update a table with another schema table using primary key(we need only update if the primary key row exists, we should not insert it).
Suppose My oracle database is TEST and i have two schema's SCHEMA1 & SCHEMA2.
SCHEMA1 & SCHEMA2 CONTAINS THE TABLE SAMPLE1
Structure:
ID NUMBER ==> PRIMARY KEY
NAME VARCHAR ==> PRIMARY KEY
LASTNAME VARCHAR ==> NORMAL COLUMN
NOW SCHEMA1 SAMPLE1 CONTAINS DATA BELOW
1) 123 'TEMP' 'TEMPOARY1'
2) 234 'TEMP2' 'TEMPORARY2'
3) 345 'TEMP3' 'TEMPORARY3'
SCHEMA2 SAMPLE1 CONTAINS DATA BELOW
1) 123 'TEMP' 'TEMP1'
2) 23 'TEMP23 'TEMP2'
3) 235 'TEMP2' 'TEMP3'
Now my target is i need to sync table SAMPLE1 of SCHEMA1 with the table of SAMPLE1 of SCHEMA2 and the result should be below.
1) 123 'TEMP' 'TEMP1'
2) 234 'TEMP2' 'TEMPORARY2'
3) 345 'TEMP3' 'TEMPORARY3'
Thank you for your help
Try something like this :
declare
procedure fncUpdate(pId PLS_INTEGER, pName VARCHAR2 , pLastname VARCHAR2) as
vIden pls_integer;
begin
UPDATE SCHEMA2.SAMPLE1 set id, name,lastname values (pId, pName pLastname)
returning iden into vIden;
DBMS_OUTPUT.PUT_LINE('iden : '|| vIden);
end fncUpdate;
begin
for cur in(
SELECT id,name,lastname
FROM SCHEMA1.SAMPLE1
)
loop
fncUpdate(cur.id,cur.name,cur.lastname);
end loop;
end;
Update of two same tables on different oracle databases
I have two schemas
I have edited your question title and changed database to schema. Since, you have clearly mentioned schema in your question body. Do not confuse between a DATABASE and a SCHEMA. I have seen SQL Server developers often interpreting a schema as a relative term for database. A schema is the set of objects (tables, views, indexes, etc) that belongs to an user. Do not confuse between a schema and database.
No need of PL/SQL. Do it in plain SQL.
You could use a MERGE statement.
For example,
MERGE INTO schema2.table2 t2
USING (SELECT * FROM schema1.table1) t1
ON (t2.primarykey = t1.key)
WHEN MATCHED THEN
UPDATE SET
t2.column2 = t1.column2
AND t2.column3 = t1.column3
/

Oracle Datatype Modifier

I need to be able to reconstruct a table column by using the column data in DBA_TAB_COLUMNS, and so to develop this I need to understand what each column refers to. I'm looking to understand what DATA_TYPE_MOD is -- the documentation (http://docs.oracle.com/cd/B19306_01/server.102/b14237/statviews_2094.htm#I1020277) says it is a data type modifier, but I can't seem to find any columns with this field populated or any way to populate this field with a dummy column. Anyone familiar with this field?
Data_type_mod column of the [all][dba][user]_tab_columns data dictionary view gets populated when a column of a table is declared as a reference to an object type using REF datatype(contains object identifier(OID) of an object it points to).
create type obj as object(
item number
) ;
create table tb_1(
col ref obj
)
select t.table_name
, t.column_name
, t.data_type_mod
from user_tab_columns t
where t.table_name = 'TB_1'
Result:
table_name column_name data_type_mod
-----------------------------------------
TB_1 COL REF
Oracle has a PL/SQL package that can be used to generate the DDL for creating a table. You would probably be better off using this.
See GET_DDL on http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_metada.htm#i1019414
And see also:
How to get Oracle create table statement in SQL*Plus

Alter column data type in production database

I'm looking for the best way to change a data type of a column in a populated table. Oracle only allows changing of data type in colums with null values.
My solution, so far, is a PLSQL statement which stores the data of the column to be modified in a collection, alters the table and then iterates over the collection, restoring the original data with data type converted.
-- Before: my_table ( id NUMBER, my_value VARCHAR2(255))
-- After: my_table (id NUMBER, my_value NUMBER)
DECLARE
TYPE record_type IS RECORD ( id NUMBER, my_value VARCHAR2(255));
TYPE nested_type IS TABLE OF record_type;
foo nested_type;
BEGIN
SELECT id, my_value BULK COLLECT INTO foo FROM my_table;
UPDATE my_table SET my_value = NULL;
EXECUTE IMMEDIATE 'ALTER TABLE my_table MODIFY my_value NUMBER';
FOR i IN foo.FIRST .. foo.LAST
LOOP
UPDATE my_table
SET = TO_NUMBER(foo(i).my_value)
WHERE my_table.id = foo(i).id;
END LOOP;
END;
/
I'm looking for a more experienced way to do that.
The solution is wrong. The alter table statement does an implicit commit. So the solution has the following problems:
You cannot rollback after alter the alter table statement and if the database crashes after the alter table statement you will loose data
Between the select and the update users can make changes to the data
Instead you should have a look at oracle online redefinition.
Your solution looks a bit dangerous to me. Loading the values into a collection and subsequently deleting them fom the table means that these values are now only available in memory. If something goes wrong they are lost.
The proper procedure is:
Add a column of the correct type to the table.
Copy the values to the new column.
Drop the old column.
Rename the new column to the old columns name.

How to set default value for column of new created table from select statement in 11g

I create a table in Oracle 11g with the default value for one of the columns. Syntax is:
create table xyz(emp number,ename varchar2(100),salary number default 0);
This created successfully. For some reasons I need to create another table with same old table structure and data. So I created a new table with name abc as
create table abc as select * from xyz.
Here "abc" created successfully with same structure and data as old table xyz. But for the column "salary" in old table "xyz" default value was set to "0". But in the newly created table "abc" the default value is not set.
This is all in Oracle 11g. Please tell me the reason why the default value was not set and how we can set this using select statement.
You can specify the constraints and defaults in a CREATE TABLE AS SELECT, but the syntax is as follows
create table t1 (id number default 1 not null);
insert into t1 (id) values (2);
create table t2 (id default 1 not null)
as select * from t1;
That is, it won't inherit the constraints from the source table/select. Only the data type (length/precision/scale) is determined by the select.
The reason is that CTAS (Create table as select) does not copy any metadata from the source to the target table, namely
no primary key
no foreign keys
no grants
no indexes
...
To achieve what you want, I'd either
use dbms_metadata.get_ddl to get the complete table structure, replace the table name with the new name, execute this statement, and do an INSERT afterward to copy the data
or keep using CTAS, extract the not null constraints for the source table from user_constraints and add them to the target table afterwards
You will need to alter table abc modify (salary default 0);
new table inherits only "not null" constraint and no other constraint.
Thus you can alter the table after creating it with "create table as" command
or you can define all constraint that you need by following the
create table t1 (id number default 1 not null);
insert into t1 (id) values (2);
create table t2 as select * from t1;
This will create table t2 with not null constraint.
But for some other constraint except "not null" you should use the following syntax
create table t1 (id number default 1 unique);
insert into t1 (id) values (2);
create table t2 (id default 1 unique)
as select * from t1;

Resources