DROP MATERIALIZED VIEW mv_name PRESERVE TABLE deletes rows in prebuilt table - sql

I created a materialized view on top of a prebuilt table.
Now I want to only drop that materialized view layer and preserve the underlying table.
I attempted to use PRESERVE TABLE clause from the information in this link, but it still deletes all the rows and returns only the template of the table after deleting the materialized view layer.
This is the script I ran:
CREATE TABLE SCHEMA.TABLE_COPY AS
(
SELECT *
FROM SCHEMA.TABLE_ORIGINAL
);
CREATE MATERIALIZED VIEW SCHEMA.TABLE_COPY
REFRESH FORCE ON DEMAND START WITH SYSDATE+0 NEXT SYSDATE+1/24
ON PREBUILT TABLE AS ( ... );
DROP MATERIALIZED VIEW SCHEMA.TABLE_COPY
PRESERVE TABLE;
SELECT *
FROM SCHEMA.TABLE_COPY;
From the last select statement, I get an empty table template with no rows. The TABLE_ORIGINAL was not empty.
Why do I get this result?
How can I fix the query to preserve the original data from the TABLE_ORIGINAL?
EDIT
So upon some testing, I found out that this only happens when I create the mv with this:
CREATE MATERIALIZED VIEW SCHEMA.TABLE_COPY
REFRESH FORCE ON DEMAND START WITH SYSDATE+0 NEXT SYSDATE+1/24
ON PREBUILT TABLE AS ( ... );
But this is fine:
CREATE MATERIALIZED VIEW SCHEMA.TABLE_COPY
ON PREBUILT TABLE AS ( ... );
So the following question would be why does this happen? And again, how could I fix this to do what I want?

Related

Materialized View by Joining View and Tables

Can we create Materialized view by joining already existing view(normal)?. My requirement is to create a MVIEW on tables(A,B) and View(c). Is it possible? If yes, do we have see any performance issue or refresh issue.
This need to done on Oracle DB.
CREATE MATERIALIZED VIEW EMP_MVIEW refresh force ON COMMIT
select
EMP.ID, EMP.NAME, DV.*
EMP_TABLE EMP
LEFT OUTER JOIN DETAILS_VIEW dv ON DV.EMP_ID=EMP.EMP_ID
First thing first, Unfortunately ANSI join syntax is not allowed for Oracle Materialized view, use the old Oracle join syntax. It is a bug in Oracle i believe so
Anything I am going to demonstrate with my answer is only regarding Materialized with FAST REFRESH option
Coming back to your original question whether we can use a normal view inside materialized view with incremental refresh capability:
Answer is No
Having said that, if we try will end up with error and unable to create it as I will demonstrate below,
Table Structure: (used only for demo as example and not actual normalized tables
CREATE TABLE emp(emp_id NUMBER primary key
,empname VARCHAR2(1000));
CREATE TABLE address_details(address_id NUMBER primary key
,address_text VARCHAR2(1000)
,emp_id NUMBER);
CREATE TABLE salary_details(sal_id NUMBER primary key
,salary NUMBER
,emp_id NUMBER);
Materialized view Logs:
--drop statements
DROP MATERIALIZED VIEW LOG ON emp;
DROP MATERIALIZED VIEW LOG ON address_details;
DROP MATERIALIZED VIEW LOG ON salary_details;
--create statements
--default
CREATE MATERIALIZED VIEW LOG ON emp;
CREATE MATERIALIZED VIEW LOG ON address_details;
CREATE MATERIALIZED VIEW LOG ON salary_details;
--with primary key (same as default above but I would stick to mention it explicitly for understanding and versioning (svn or git) purpose
CREATE MATERIALIZED VIEW LOG ON emp WITH PRIMARY KEY;
CREATE MATERIALIZED VIEW LOG ON address_details WITH PRIMARY KEY;
CREATE MATERIALIZED VIEW LOG ON salary_details WITH PRIMARY KEY;
--with primary key and rowid
CREATE MATERIALIZED VIEW log ON emp WITH PRIMARY KEY, ROWID;
CREATE MATERIALIZED VIEW log ON address_details WITH PRIMARY KEY, ROWID;
CREATE MATERIALIZED VIEW log ON salary_details WITH PRIMARY KEY, ROWID;
1. First try creating MV with normal view as you want:
CREATE OR REPLACE VIEW DETAILS_VIEW AS
SELECT sal_id
,salary
,address_id
,address_text
,sl.emp_id
--,sl.rowid sl_rowid
--,ad.rowid ad_rowid
FROM salary_details sl
,address_details ad
WHERE sl.emp_id = ad.emp_id;
DROP MATERIALIZED VIEW emp_mview;
CREATE MATERIALIZED VIEW EMP_MVIEW
REFRESH FORCE ON COMMIT
AS
SELECT emp.emp_id
,emp.empname
,dv.sal_id
,dv.salary
,dv.address_id
,dv.address_text
--,emp.rowid emp_rowid
--,dv.sl_rowid
--,dv.ad_rowid
FROM emp emp
,details_view dv
WHERE emp.emp_id = dv.emp_id(+);
Result:
ORA-12054: cannot set the ON COMMIT refresh attribute for the materialized view
Believe me I have tried with all scenarios creating log with primary key and rowid and adding the rowid to the select clause and nothing works
Moving forward:
2. Second try creating MV with standard joins from oracle by putting all individual base tables in the from clause:
I have created the materialized view logs with option primary key as I mentioned in Materialized view Logs section above.
CREATE MATERIALIZED VIEW EMP_MVIEW
REFRESH FORCE ON COMMIT
AS
SELECT emp.emp_id
,emp.empname
,sl.sal_id
,sl.salary
,ad.address_id
,ad.address_text
FROM emp emp
,salary_details sl
,address_details ad
WHERE emp.emp_id = sl.emp_id(+)
AND emp.emp_id = ad.emp_id(+);
BINGO: Materialized view created ,
But, wait wait... Does it mean now I can do a FAST REFRESH ? Lets check:
We can Analyzing Materialized View Capabilities using DBMS_MVIEW.EXPLAIN_MVIEW which will insert capabilities details to table called MV_CAPABILITIES_TABLE (available with # $ORACLE_HOME/rdbms/admin/utlxmv.sql). If we don't have the script and grants from DBA you need to get it. However I will anyhow give the scripts below as well
HOW TO ANALYSE CAPABILITY OF MV:
--table structure
CREATE TABLE mv_capabilities_table (
statement_id VARCHAR2(30),
mvowner VARCHAR2(30),
mvname VARCHAR2(30),
capability_name VARCHAR2(30),
possible CHAR(1),
related_text VARCHAR2(2000),
related_num NUMBER,
msgno INTEGER,
msgtxt VARCHAR2(2000),
seq NUMBER
);
--delete always before analyzing for a view to have only rows for a specific and not to have where clause to filter :)
DELETE FROM mv_capabilities_table;
--run this script which will analyze and insert into mv_capabilities_table
BEGIN
dbms_mview.explain_mview('EMP_MVIEW');
END;
/
/***ANALYSIS RESULT:***/
--I am intersted only with data related to FAST REFRESH category
SELECT capability_name
,possible
,substr(msgtxt
,1
,60) AS msgtxt
FROM mv_capabilities_table
WHERE capability_name LIKE '%FAST%';
/**
CAPABILITY_NAME POSSIBLE MSGTXT
REFRESH_FAST N
REFRESH_FAST_AFTER_INSERT N the SELECT list does not have the rowids of all the detail t
REFRESH_FAST_AFTER_INSERT N mv log must have ROWID
REFRESH_FAST_AFTER_INSERT N mv log must have ROWID
REFRESH_FAST_AFTER_INSERT N mv log must have ROWID
REFRESH_FAST_AFTER_ONETAB_DML N see the reason why REFRESH_FAST_AFTER_INSERT is disabled
REFRESH_FAST_AFTER_ANY_DML N see the reason why REFRESH_FAST_AFTER_ONETAB_DML is disabled
REFRESH_FAST_PCT N PCT FAST REFRESH is not possible if query contains LEFT OUTE
**/
If you look at the result with text **mv log must have ROWID**Above result of analysis tells us the materialized view logs are missing the ROWID option and thus FAST REFRESH is not possible.
Note: Other columns in mv_capabilities_table will also tell you the exact tables which i have not included and you can check and test by yourself to see.
Moving forward..
3. Third try creating MV with standard joins from oracle and MV Logs with option ROWID included:
steps: (will not provide the scripts again but just providing the steps to simulate
I will drop and re-create the MV logs with option ROWID as mentioned in Materialized view Logs section above.
Then I will drop and re-create the same MV definition I used in my 2nd try which will be eventually created
Next I will try to repeat the steps to analyze the MV as described in HOW TO ANALYSE CAPABILITY OF MV section
What do i get in my analysis report:
/**
CAPABILITY_NAME POSSIBLE MSGTXT
REFRESH_FAST N
REFRESH_FAST_AFTER_INSERT N the SELECT list does not have the rowids of all the detail t
REFRESH_FAST_AFTER_ONETAB_DML N see the reason why REFRESH_FAST_AFTER_INSERT is disabled
REFRESH_FAST_AFTER_ANY_DML N see the reason why REFRESH_FAST_AFTER_ONETAB_DML is disabled
REFRESH_FAST_PCT N PCT FAST REFRESH is not possible if query contains LEFT OUTE
**/
Ufffff: I am tired actually and again the MV is not having the FAST REFRESH capable yet and the reason tells us "the SELECT list does not have the rowids of all the detail tables"
What it means: the next criteria for FAST REFRESH is Rowids of all the tables in the FROM list must appear in the SELECT list of the query
So,
4. Fourth and last try creating MV with standard joins from oracle and MV Logs with option ROWID included and also the details tables rowids are now included in the select clause:
steps:
As with 3rd try the MV logs required for first refresh are in place I will drop and re-create the MV again but this time with adding the rowids of detail table.
MV Final Script:
CREATE MATERIALIZED VIEW EMP_MVIEW
REFRESH FORCE ON COMMIT
AS
SELECT emp.emp_id
,emp.empname
,sl.sal_id
,sl.salary
,ad.address_id
,ad.address_text
,emp.rowid emp_rowid
,sl.rowid sl_rowid
,ad.rowid ad_rowid
FROM emp emp
,salary_details sl
,address_details ad
WHERE emp.emp_id = sl.emp_id(+)
AND emp.emp_id = ad.emp_id(+);
Now as the MV created , lets analyse the capabilities of the MV as described in HOW TO ANALYSE CAPABILITY OF MV section one more time. (fingers crossed)
Result:
SELECT capability_name
,possible
,substr(msgtxt,1,60) AS msgtxt
FROM mv_capabilities_table
WHERE capability_name LIKE '%FAST%';
/**
CAPABILITY_NAME POSSIBLE MSGTXT
REFRESH_FAST Y
REFRESH_FAST_AFTER_INSERT Y
REFRESH_FAST_AFTER_ONETAB_DML Y
REFRESH_FAST_AFTER_ANY_DML Y
REFRESH_FAST_PCT N PCT FAST REFRESH is not possible if query contains LEFT OUTE
**/
Finally the REFRESH_FAST capability is possible as we can see POSSIBLE -> Y
Sorry for long answer but I thought I should put how I learn the things about in MV in past which could be useful to share.
Some Links I found always useful with respect to Oracle materialized view:
Official site from oracle
MV with Warehouse Oracle Official site
Oracle base
My Favorite from Alberto Dell'Era
One good SO answer about MV
Cheers!!

Creating a VIEW in SQL-Server

I'm trying to create a VIEW in my database, and it shows me
"Incorrent syntax error"
Am I doing something wrong?
You selected two select statements. You should run only statement starting from Create View till where clause.
create view view_name as select id from tab where id = some_id;
Just run one statement of create view that's it.
Include GO between your Create View and Select query (or) view should be the only statement.
CREATE VIEW [dbo].[View_name] As
-- view logic
GO
Select * from table

Create temporary table from view

I am using sqlite3.
Suppose I have a view view_intermediate. I would like to create a temporary table from this view. In other words, turn the result of the view into a temporary table.
How should the SQL statement look like to do this?
SQLite supports CREATE TABLE AS..SELECT, so assuming you want the data in the table:
CREATE TABLE myTable AS
SELECT *
FROM view_intermediate;
If you want a table to be created from the view, but don't want the data, you can add a false condition.
CREATE TABLE myTable AS
SELECT *
FROM view_intermediate
WHERE 1=2;

Not able to re-create materialized view on prebuilt table

Steps I am trying to execute:
CREATE TABLE sample.MV(application_mode varchar2(25));
CREATE MATERIALIZED VIEW sample.MV
ON PREBUILT TABLE
REFRESH FORCE ON DEMAND
AS
SELECT application_mode
FROM sample.tbl_name
WHERE cnt > 0;
When any other user is trying to drop and re-create the MV
DROP MATERIALIZED VIEW sample.MV;
CREATE MATERIALIZED VIEW sample.MV
ON PREBUILT TABLE
REFRESH FORCE ON DEMAND
AS
SELECT application_mode
FROM sample.tbl_name
WHERE cnt > 0;
He gets below error while re-creation:
ORA-32334: cannot create prebuilt materialized view on a table already
referenced by a MV
why is so?
User got a work around for the same which is to drop the table first
and then recreate the table, recreate the MV.
Really weird behaviour of oracle is that all the subsequent attempts of that user of dropping and re-creating MV work well with no error.
update 2: it really is connected to some other mview which directly or indirectly uses/used this one. (as suggested by #Marmite Bomber, but his all_snapshots based query does not help)
You can find it out with user_dependencies (or maybe all_dependencies) using something like the following query. You may have to follow some dependency graph over synonyms, views, functions etc. to find the connection.
(In my case I knew that there had been a dependency before dropping the matview with preserve table. So this table is still "somehow connected" to some depending "higher" matview and thus the error seems to be issued.)
select * from user_dependencies
where 1=1 -- for easier comment filter usage below
--and referenced_owner=user -- if only current user relevant
--and not type in ('TRIGGER') -- e.g. to skip some auto-gen. triggers
and referenced_name = '<my matview>'
order by name, referenced_name
So a working solution was to also drop the "higher"/depending mview(s) (e.g. with the preserve table option) and recreate them (e.g. with the prebuilt table option so there is no rebuilt necessary).
Previous/old findings/workarounds:
I had the same problem where I automatically "renamed" some materialized views, which is programatically not possible (11.2).
So I created new matviews from old ones
deleting them, but not the table data (preserve table) and
reassociating the existing table with the new ones (prebuilt table).
Everything worked fine but for one matview that caused this ORA-32334 :-(
Debugging with the following SQLs did not give a clue why the system thinks this table is still associated with some matview so I can only assume it is a bug with some kind of random behaviour:
select * from user_mviews
select * from user_objects
where object_name like '%<some meaningful filter criteria>%'
order by object_type, object_name
My workaround: recreating the specific mview from scratch.
The problem with ORA-32334 is that you have nested materialized views.
A possible scenario is as follows - your materialized view MV is referenced by other materialized view MV2
create table mv as
SELECT max(application_mode) application_mode
FROM tbl_name
WHERE cnt > 0
GROUP BY modes;
CREATE MATERIALIZED VIEW MV
ON PREBUILT TABLE
REFRESH FORCE ON DEMAND
AS
SELECT application_mode
FROM tbl_name
WHERE cnt > 0
;
create MATERIALIZED VIEW MV2
REFRESH FORCE ON DEMAND
AS
SELECT *
FROM MV
;
The DROP of MVis not a problem...
DROP MATERIALIZED VIEW MV;
But re-creation gives error:
CREATE MATERIALIZED VIEW MV
ON PREBUILT TABLE
REFRESH FORCE ON DEMAND
AS
SELECT application_mode
FROM tbl_name
WHERE cnt > 0
;
SQL-Fehler: ORA-32334: cannot create prebuilt materialized view on a table already referenced by a MV
The key is in already referenced by a MV
So let find the materialized view that is causing the problem:
select name, owner, master_owner, master
from all_snapshots where
master ='MV';
NAME OWNER MASTER_OWNER MASTER
------------------------------ ------------------------------ ------------------------------ ------------------------------
MV2 SAMPLE SAMPLE MV
The MV2 must be dropped first
DROP MATERIALIZED VIEW MV2;
Than the materializes view MV can be rebuilt.
CREATE MATERIALIZED VIEW MV
ON PREBUILT TABLE
REFRESH FORCE ON DEMAND
AS
SELECT application_mode
FROM tbl_name
WHERE cnt > 0
;
and after that the MV2 must be build again.
This is the expected bahaviour on 11.2
select * from v$version;
Oracle Database 11g Express Edition Release 11.2.0.2.0 - Production
Define a table MV and build a materialized view on it.
create table mv as
SELECT application_mode
FROM tbl_name
WHERE cnt > 0
;
CREATE MATERIALIZED VIEW MV
ON PREBUILT TABLE
REFRESH FORCE ON DEMAND
AS
SELECT application_mode
FROM tbl_name
WHERE cnt > 0
;
Now check that both object exĂ­sts
select object_type, object_name from user_objects where object_name = 'MV';
OBJECT_TYPE OBJECT_NAME
------------------- -----------
TABLE MV
MATERIALIZED VIEW MV
Now drop the materialzed view and re-check the objects
DROP MATERIALIZED VIEW MV;
select object_type, object_name from user_objects where object_name = 'MV';
OBJECT_TYPE OBJECT_NAME
------------------- -----------
TABLE MV
OK, materialized view disapeared, but table exists, why?
You may want to check documentation here
If you drop a materialized view that was created on a prebuilt table, then the database drops the materialized view, and the prebuilt table reverts to its identity as a table.
So, the table exists and you may again build a materialized view on it.
CREATE MATERIALIZED VIEW MV
ON PREBUILT TABLE
REFRESH FORCE ON DEMAND
AS
SELECT application_mode
FROM tbl_name
WHERE cnt > 0
;
select object_type, object_name from user_objects where object_name = 'MV';
OBJECT_TYPE OBJECT_NAME
------------------- -----------
TABLE MV
MATERIALIZED VIEW MV
Note in your case when teh materialized view is based on prebuilt table the "PRESERVE TABLE" is default behaviour in DROP, so teh same effect you get with
DROP MATERIALIZED VIEW MV PRESERVE TABLE;
select object_type, object_name from user_objects where object_name = 'MV';
OBJECT_TYPE OBJECT_NAME
------------------- -----------
TABLE MV
The table exist after the DROP materialize view.
Please check this simple scenario to see if it works. Check also your Oracle version - PRESERVE TABLEwas introduced in 10g.

SQL.Working with views

I have a table 'Goods' with different information about goods (name, price, etc). I need to create a view at the same scheme as table 'Goods' has. But the view must be empty. And when user adds new good to the view it is saved in table 'Goods', but the view remains empty when user opens it next time. So main idea is not to show existing data to the user which has access to the view.
Assuming your on a database system that supports a concept like SQL Server's CHECK OPTION, and you're allowed to create a view that doesn't have that option set, you should be fine:
create table T (ID int not null)
go
create view V
as
select * from T where 1=0
go
select * from V
go
insert into V(ID) values (10)
go
select * from V
go
select * from T
The two selects from V return 0 rows. The select from T returns one row:
ID
----
10
CHECK OPTION:
Forces all data modification statements executed against the view to follow the criteria set within select_statement. When a row is modified through a view, the WITH CHECK OPTION makes sure the data remains visible through the view after the modification is committed.
And you want the opposite - you want to allow data modifications performed through the view to create rows which are invisible through the view.
Create table Goods1 with "insert trigger" on it which make insert into Goods and delete from Goods1
As far as I know this isn't possible. The whole point of a view is that it is a view to a table or grouping of tables, ie. it must show the data that matches the view.
http://www.w3schools.com/sql/sql_view.asp
What you could do is create another table called GoodsView and add a trigger to it to INSERT into Goods table and DELETE from GoodsView afterwards.
http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Fsqlp%2Frbafysqltrig.htm