Oracle - I can't use Materialized View's PREBUILD statement with other MV clauses - oracle

I'm trying to build a Materialized View on top of a prebuilt table. I can use the below syntax with no modifiers and it works fine.
CREATE MATERIALIZED VIEW TESTRESULT
ON PREBUILT TABLE
SELECT ...
FROM ...
WHERE ...
However, when adding extra clauses to the Materialized View, I get the error "Missing Keyword". I'm not sure what I'm missing and I can't find any documentation online in conjunnction with building on top of a prebuilt table and adding extra clauses.
CREATE MATERIALIZED VIEW TESTRESULT
NOCACHE
LOGGING
NOCOMPRESS
NOPARALLEL
BUILD IMMEDIATE
REFRESH FORCE ON DEMAND
WITH PRIMARY KEY
ON PREBUILT TABLE
AS
SELECT ...
FROM ...
WHERE ...
Oracle Verision : 10g

The ON PREBUILT TABLE option is not compatible with some of your options, as described in the CREATE MATERIALIZED VIEW documentation:
The CACHE, LOGGING, PARALLEL and COMPRESS are table properties inherited from the already built table and are therefore incompatible with PREBUILT.
the BUILD option is there to specify when the table must be populated. However the table is already populated since you've used the PREBUILT option, and the two options are therefore incompatible.
Also make sure you have the arguments is the right order.
The following works:
SQL> CREATE TABLE TEST(ID NUMBER PRIMARY KEY);
Table created
SQL> CREATE TABLE testresult(ID NUMBER);
Table created
SQL> CREATE MATERIALIZED VIEW TESTRESULT
2 ON PREBUILT TABLE
3 REFRESH FORCE ON DEMAND
4 WITH PRIMARY KEY
5 AS
6 SELECT ID
7 FROM TEST;
Materialized view created

Related

Domain index in materialized view return zero rows

I have problem with Oracle DB - domain index returns zero rows after search by CONTAINS() on materialized view. I see that materialized view is filled with data and I also used procedure ctx_ddl.sync_index() for domain index synchronization.
What works good:
CREATE TABLE
INSERT DATA
CREATE DOMAIN INDEX
SYNC DOMAIN INDEX
FIND ROWS BY CONTAINS - RETURN ROWS
What is not working:
CREATE TABLE
INSERT DATA
CREATE MATERIALIZED VIEW
REFRESH MATERIALIZED VIEW
CREATE DOMAIN INDEX IN MATERIALIZED VIEW
SYNC DOMAIN INDEX IN MATERIALIZED VIEW
FIND ROWS BY CONTAINS IN MATERIALIZED VIEW - RETURN ZERO ROWS (LIKE %TERM% WORKS)
Why everything works fine without materialized view?
Here is my queries (you can copy-paste and try it in your oracle db):
--create table
CREATE TABLE "PCOUNTERPARTY" ( "ID_COUNTERPARTY" NUMBER(10,0), "TXT_SEARCH_FULL_NAME" NVARCHAR2(260), CONSTRAINT "PCOUNTERPARTY_PK" PRIMARY KEY ("ID_COUNTERPARTY"));
--INSERT DATA.
Insert into PCOUNTERPARTY (ID_COUNTERPARTY,TXT_SEARCH_FULL_NAME) values (1184,'MARTINKO3');
--create materialized view
CREATE MATERIALIZED VIEW m_pcounterparty
AS
SELECT c.ID_COUNTERPARTY, CAST( c.TXT_SEARCH_FULL_NAME AS varchar2(260 CHAR) ) as txt_search_full_name_all
FROM PCOUNTERPARTY c;
--create domain index
create index IDXM_1_pcounterparty on m_pcounterparty(TXT_SEARCH_FULL_NAME_ALL) indextype is ctxsys.context PARAMETERS ('SYNC ( ON COMMIT)');
--refresh of materialized view
EXECUTE DBMS_MVIEW.REFRESH('M_PCOUNTERPARTY');
--refresh of index
exec ctx_ddl.sync_index('IDXM_1_pcounterparty');
--search in materialized view
SELECT
TXT_SEARCH_FULL_NAME_ALL
from
M_PCOUNTERPARTY c
WHERE
CONTAINS(c.TXT_SEARCH_FULL_NAME_ALL, 'martin', 1) > 0; --return ZERO and THIS IS PROBLEM
--c.TXT_SEARCH_FULL_NAME_ALL LIKE '%MARTIN%'; -- return rows but we want search thru CONTAINS
Oracle Text indexes normally search words, not strings.
A wildcard is not necessary to search for "martin" in "Martin Luther King Jr." But a wildcard is necessary to search for "martin" in "MARTINKO3".
Change the CONTAINS predicate to this:
CONTAINS(c.TXT_SEARCH_FULL_NAME_ALL, 'martin%', 1) > 0;
I ran tests on Oracle 12.2 and could not find any differences in behavior between using a table or a materialized view. Perhaps there was a test mistake or a very specific bug that caused the text indexes to act differently on your system.

Materialized View Refresh with changing synonym pointer in SQL

I have two tables, TABLE_1 and TABLE_2. Then we have a synonym called TABLE that points to either TABLE_1 or TABLE_2. When TABLE_1 is active, an ETL populates TABLE_2 and when the run is complete, it switches the TABLE synonym to TABLE_2 to make it the active table. Then I have a materialized view that does something like this as the SQL: select * from TABLE. What I am seeing happen is that after the materialize view runs the first time, it caches the actual table the synonym is pointing too. So when the ETL runs and flips the synonym to point at TABLE_2, when a complete refresh is done on the materialized view, it still thinks the synonym is pointed at TABLE_1. Why when I do a complete refresh does the materialized view not pick up the new synonym pointer to TABLE_2?
Here is a workaround to Oracle's bug:
alter materialized view MV_NAME nocache;
BEGIN DBMS_SNAPSHOT.REFRESH( MV_NAME,'C'); end;
alter materialized view MV_NAME cache;
I cannot find anything useful in Oracle documentation but just enable the logic:
I firstly create materialized view
In reality to support this materialized view Oracle makes the TABLE with some specific structure (dependent on your query structure) and the rule to refresh the table (as far as I remember it is called SUMMARY, but the name does not play any role here)
I change synonym target to the table which has another structure
The new target table is not "fitting" to the previous structure (e.g. it has totally different amount/data types of columns), the previous structure is invalid then and not working anymore. The underground table must be recreated then.
That's why I would say it is the only way to prevent the errors: reference the real target instead of synonym for creating materialized view.
So, the answer is: because the materialized view is a static table-like object dependent on the data set it is selecting; that's why to prevent the inconsistencies materialized view references the real object.
Sometimes I really wonder how many details Oracle hides inside.

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');

Query too complex for a simple join [duplicate]

So I'm pretty sure Oracle supports this, so I have no idea what I'm doing wrong. This code works:
CREATE MATERIALIZED VIEW MV_Test
NOLOGGING
CACHE
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS
SELECT V.* FROM TPM_PROJECTVERSION V;
If I add in a JOIN, it breaks:
CREATE MATERIALIZED VIEW MV_Test
NOLOGGING
CACHE
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS
SELECT V.*, P.* FROM TPM_PROJECTVERSION V
INNER JOIN TPM_PROJECT P ON P.PROJECTID = V.PROJECTID
Now I get the error:
ORA-12054: cannot set the ON COMMIT refresh attribute for the materialized view
I've created materialized view logs on both TPM_PROJECT and TPM_PROJECTVERSION. TPM_PROJECT has a primary key of PROJECTID and TPM_PROJECTVERSION has a compound primary key of (PROJECTID,VERSIONID). What's the trick to this? I've been digging through Oracle manuals to no avail. Thanks!
To start with, from the Oracle Database Data Warehousing Guide:
Restrictions on Fast Refresh on Materialized Views with Joins Only
...
Rowids of all the tables in the FROM list must appear in the SELECT
list of the query.
This means that your statement will need to look something like this:
CREATE MATERIALIZED VIEW MV_Test
NOLOGGING
CACHE
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS
SELECT V.*, P.*, V.ROWID as V_ROWID, P.ROWID as P_ROWID
FROM TPM_PROJECTVERSION V,
TPM_PROJECT P
WHERE P.PROJECTID = V.PROJECTID
Another key aspect to note is that your materialized view logs must be created as with rowid.
Below is a functional test scenario:
CREATE TABLE foo(foo NUMBER, CONSTRAINT foo_pk PRIMARY KEY(foo));
CREATE MATERIALIZED VIEW LOG ON foo WITH ROWID;
CREATE TABLE bar(foo NUMBER, bar NUMBER, CONSTRAINT bar_pk PRIMARY KEY(foo, bar));
CREATE MATERIALIZED VIEW LOG ON bar WITH ROWID;
CREATE MATERIALIZED VIEW foo_bar
NOLOGGING
CACHE
BUILD IMMEDIATE
REFRESH FAST ON COMMIT AS SELECT foo.foo,
bar.bar,
foo.ROWID AS foo_rowid,
bar.ROWID AS bar_rowid
FROM foo, bar
WHERE foo.foo = bar.foo;
Have you tried it without the ANSI join ?
CREATE MATERIALIZED VIEW MV_Test
NOLOGGING
CACHE
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS
SELECT V.*, P.* FROM TPM_PROJECTVERSION V,TPM_PROJECT P
WHERE P.PROJECTID = V.PROJECTID
You will get the error on REFRESH_FAST, if you do not create materialized view logs for the master table(s) the query is referring to. If anyone is not familiar with materialized views or using it for the first time, the better way is to use oracle sqldeveloper and graphically put in the options, and the errors also provide much better sense.
The key checks for FAST REFRESH includes the following:
1) An Oracle materialized view log must be present for each base table.
2) The RowIDs of all the base tables must appear in the SELECT list of the MVIEW query definition.
3) If there are outer joins, unique constraints must be placed on the join columns of the inner table.
No 3 is easy to miss and worth highlighting here
USE THIS CODE
CREATE MATERIALIZED VIEW MV_ptbl_Category2
BUILD IMMEDIATE
REFRESH FORCE
ON COMMIT
AS
SELECT *
FROM ptbl_Category2;
Note- MV_ptbl_Category2 is the Materialized view name
Ptbl is the table name.

Oracle: Recreate database view after modifying varchar column size

I've made some changes to columns in a database table (increasing the size of varchar), however I need to have the view of the table refreshed to pick up this change. In SQL server 2005 I would use the script to -> alter to recreate the script for the view. I'm trying to figure out what the Oracle SQL command would be to rebuild the view to display the change of the column?
Unless your view is explicitly restricting the size of the column, it will pick up the change automatically. It may have been invalidated by the table change but would be automatically recompiled when first used; or can be manually recompiled with alter view <view name> compile.
If you do so:
create table sample_table(text varchar2(10));
insert into sample_table (text) values('text...');
create view sample_view as select * from sample_table;
select * from sample_view;
alter table sample_table modify text varchar2(200);
You do not do anything to promote this change in view in Oracle database.
Or you can use "ALTER VIEW sample_view COMPILE" (how wrote #AlexPole or #devio). Oracle do this automatically when you firstly use select on sample_view after alter table.
Try
ALTER VIEW MyView COMPILE;

Resources