Oracle - Materialized View confusion (is Toad IDE wrong in displaying MV in Tables section?) - oracle

I'm confused about Materialized views. Either it is the Toad IDE that I am using that is confusing me, or its that I don't understand MVs enough.
I created a materialized view in Oracle by something like this....
CREATE MATERIALIZED VIEW TESTRESULT
NOCACHE
LOGGING
NOCOMPRESS
NOPARALLEL
BUILD IMMEDIATE
REFRESH FORCE ON DEMAND
WITH PRIMARY KEY
AS
SELECT ...
FROM tables...
I would expect that the materialized view would be created and populated with the data returned from the query. Okay, not a big deal.
What I am confused on is why my Toad IDE shows a table 'TESTRESULT' under the tables section. It even has a 'Create Table Script' that I can look at.
But I also see my materialized view under the 'Materialized View' section.
Behind the scenes is Oracle creating a table when I create a materialized view? It looks as if there are two seperate objects, a materialized view and a table? Could someone please explain what is going on here behind the scenes when creating a materialized view? Is Toad wrong or am I misunderstanding something?
Toad version: 9.6.1.1
Oracle: 10g

Yes, behind the scenes, Oracle creates two objects, a table where the results are actually materialized and a materialized view that has all the metadata (the query, the attributes, etc.). It's very similar to what happens when you create a unique constraint-- Oracle creates a unique index with the same name as the constraint to actually enforce the constraint and then it creates a constraint itself. If you create a materialized view on a pre-built table, you can end up with different names for the table and for the materialized view just as you could create a constraint that uses an existing index that has a different name.
SQL> select object_name, object_type
2 from user_objects
3
SQL> ed
Wrote file afiedt.buf
1 select object_name, object_type
2 from user_objects
3* where object_name = 'MV_EMP'
4 /
no rows selected
SQL> create materialized view mv_emp
2 as
3 select *
4 from emp;
Materialized view created.
SQL> column object_name format a30;
SQL> select object_name, object_type
2 from user_objects
3 where object_name = 'MV_EMP';
OBJECT_NAME OBJECT_TYPE
------------------------------ -------------------
MV_EMP TABLE
MV_EMP MATERIALIZED VIEW

Related

How to add primary key to materialized view in oracle

please help me with an example on how to add primary key to materialized view in oracle 19c or 21c.
Also, real life application where we use primary key to materialized view. I posting this after complete research on materialized view.
I have a strong opinion that primary key is not required on materialized view. Please correct me if I am wrong.
How to add a primary key? Using the ALTER TABLE statement.
This is a sample table; I'll create a materialized view on it.
SQL> create table test as
2 select deptno, empno, ename, job
3 from emp;
Table created.
SQL> create materialized view mv_test as
2 select deptno, empno, ename, job
3 from test;
Materialized view created.
Primary key:
SQL> alter table mv_test add constraint pk_mvt primary key (empno);
Table altered.
SQL>
Real life: use it whenever appropriate. Primary key implicitly creates index on primary key column(s). Index improves performance (if optimizer chooses to use it).

Oracle : table always "exist" after drop table

I'm using Oracle and I have a strange thing.
I dropped a table using :
drop table t_my_table, and committed.
But when I launch select * from t_my_table, it shows the data, as if the table is not dropped.
I tried disconnecting and reconnecting, it stills shows the data when I select.
And when I once again try with :
drop table t_my_table, it tells me that this table does not exist.
But if I run select again, the data is always there.
How is this possible ?
Thank you.
You mean this case?
create view t_my_table as
select 'I''m here' as txt from dual;
drop table t_my_table;
ORA-00942: table or view does not exist
But
select * from t_my_table;
TXT
--------
I'm here
solution of the most probably cause
select OBJECT_TYPE from user_objects where object_name = 'T_MY_TABLE';
OBJECT_TYPE
-------------------
VIEW
You defined a view (or other object type other than TABLE), that can't be dropped with DROP TABLE, but can be selected.
Simple check in USER_OBJECTS the OBJECT_TYPE. You may alternatively see also SYNONYM as proposed in other answer.
Note that it is not a MATERIALIZED VIEW as if you try to drop a Materialized View with DROP TABLE a different error message is raised:
ORA-12083: must use DROP MATERIALIZED VIEW to drop T_MY_TABLE
What does this return?
select * from all_synonyms
where synonym_name = 'T_MY_TABLE';
I suspect there is a synonym T_MY_TABLE that points to a table in a different schema.
drop table t_my_table purge;
Specify PURGE if you want to drop the table and release the space associated with it in a single step. If you specify PURGE, then the database does not place the table and its dependent objects into the recycle bin.
...
Using this clause is equivalent to first dropping the table and then purging it from the recycle bin. This clause lets you save one step in the process. It also provides enhanced security if you want to prevent sensitive material from appearing in the recycle bin.
Probably something different is happening.
Normal case would be:
SQL> create table t1 as select 1 a from dual;
Table T1 created.
SQL> drop table t1;
Table T1 dropped.
SQL> select * from t1;
Error starting at line : 22 in command -
select * from t1
Error at Command Line : 22 Column : 20
Error report -
SQL Error: ORA-00942: table or view does not exist
00942. 00000 - "table or view does not exist"
*Cause:
*Action:
So what was the message after the drop table?
Is t_my_table really a table?
Try select * from all_objects where lower(object_name) = 't_my_table'

oracle database to find recently added column in table or database(oracle)

I want to find the recently added column to existing table.
How to find recently added column in table or database(oracle).
Recently the table and the databases of our web application got modified and some of the table got altered.
Ideally you should have restricted access to your Production database, together with a build process which applies scripts out of source control, rather than allowing people to change things using TOAD. It's pretty hard to conduct forensics in a free-fire zone.
You can find out which tables have changed by interrogating the data dictionary:
SQL> select object_name from user_objects t
2 where t.object_type = 'TABLE'
3 and t.last_ddl_time > trunc(sysdate)
4 /
no rows selected
SQL> alter table t23 add col_3 number
2 /
Table altered.
SQL> select object_name from user_objects t
2 where t.object_type = 'TABLE'
3 and t.last_ddl_time > trunc(sysdate)
4 /
OBJECT_NAME
----------------------------------------------------------
T23
SQL>
This won't tell you what the change was, or who did it. To get better information you need a proper audit trail. At the very least you should enable auditing of DDL statements....
SQL> audit ALTER TABLE;
Audit succeeded.
SQL>
Find out more.

Oracle More than one materialized view on a materialized log

I would like to have more than one materialized view with refresh fast on commit.
For "refresh fast on commit" you need a materialized view log. Obviously a refresh fast on commit needs the log. The question is can I have more than one materialized view accessing the log.
Obviously I still need the log to satisfy the normal prerequisites (across all views):
http://docs.oracle.com/cd/B19306_01/server.102/b14223/basicmv.htm
Cheers for any help in advance.
Absolutely.
create table data_table as (
select *
from dba_users
);
alter table data_table
add constraint data_table_test_pk PRIMARY KEY (user_id);
select * from data_table;
So now we have a table that looks like dba_users with a PRIMARY KEY constraint.
create materialized view log on data_table;
create materialized view mat_view_one
refresh fast on commit
as
select username, user_id
from data_table
;
create materialized view mat_view_two
refresh fast on commit
as
select user_id, username, account_status
from data_table;
There's our log and the 2 views create successfully.
SYS record in the test table:
select * from mat_view_one
where user_id=0;
USERNAME USER_ID
------------------------------ ----------
SYS 0
select * from mat_view_two
where user_id=0;
USER_ID USERNAME ACCOUNT_STATUS
---------- ------------------------------ --------------------------------
0 SYS OPEN
Now lets update the SYS's name and commit and see what our views show:
update data_table
set username='WALTERWHITE'
WHERE USER_ID=0
;
COMMIT;
USERNAME USER_ID
------------------------------ ----------
WALTERWHITE 0
USER_ID USERNAME ACCOUNT_STATUS
---------- ------------------------------ --------------------------------
0 WALTERWHITE OPEN
So yes, absolutely. 1 materialized view log can serve as many materialized views as you need so long as the proper constraints are held.
Yes. A materialized view log can support as many materialized views as you'd like.
Supporting multiple materialized views may cause the log to be larger than it would be if it was supporting a single materialized view though that probably isn't terribly significant here since your logs probably won't store the data long. If you're replicating data to remote databases (which by definition you can't do with a fast refreshable materialized view), it can be a bit tricky if one of the remote materialized views stops refreshing or goes away without the source being aware since it can cause data to queue up indefinitely in the log. But, again, that doesn't sound like the situation you're facing.

Redefine materialized view with no downtime

I have a materialized view that I need to redefine the SQL for. We have an external system that hits the view over a db link, and the monster view takes 5 minutes to refresh the data in the view. The only way I know how to redefine the SQL for a view is to drop it and recreate it, but it would be very bad if the external system couldn't find the table, or it didn't have a complete data set. I need to have as little downtime as possible.
Is there any way to do this natively or more elegantly than:
Create public synonym for materialized view and make everything that uses the view use the synonym instead.
Create new materialized view with new SQL
Change the synonym to point to the new view
Drop the old view.
I've got code to do this dynamically but it is getting really ugly. It seems like there should be a better way to handle this.
Oracle has a build in solution for that. Keep in mind that the mview declaration is separate from that of the table.
The original mview
create materialized view mv1 as select dept , count(*) as cnt from scott.emp;
we want to change the declaration so that only dept over 5 will be calculated
drop materialized view mv1 preserve table;
notice the PRESERVE TABLE clause - the table mv1 is not droped - only the mview layer.
desc mv1
now we create the mview with a different query on top of the existing table
create materialized view mv1 on prebuilt table as
select dept , count(*) as cnt from scott.emp where dept > 5;
notice the on prebuilt table clause. the mview is using the existing object.
exec dbms_mview.refresh_mview('mv1');

Resources