What's wrong with this fast refreshable view definition: it is not complex and complete, however ORA-12015 is raised - oracle

What's wrong with this fast refreshable view definition in Oracle 10.2:
create table A
(
ID number(19,0) not null constraint A_PK primary key using index
, C number(9,0) not null
);
create table B
(
ID number(19,0) not null constraint B_PK primary key using index
, A_ID number(19,0) not null constraint A_FK references A(ID) on delete cascade
, D number(9,0) not null
);
create index B_FK_IDX on B(A_ID);
create materialized view log on A
with primary key, rowid, sequence (C) including new values;
create materialized view log on B
with primary key, rowid, sequence (A_ID, D) including new values;
create materialized
view X
refresh fast with primary key
as
select A.ID as A_ID
, A.ROWID as A_ROWID
, B.ID as B_ID
, B.ROWID as B_ROWID
, A.C
, B.D
from A
inner join
B
on B.A_ID = A.ID;
When the script is executed I get:
table A created.
table B created.
index B_FK_IDX created.
materialized view LOG created.
materialized view LOG created.
...[view definition and local error message left out]
SQL-Error: ORA-12015: cannot create a fast refresh materialized view from a complex query
12015. 00000 - "cannot create a fast refresh materialized view from a complex query"
*Cause: Neither ROWIDs and nor primary key constraints are supported for
complex queries.
*Action: Reissue the command with the REFRESH FORCE or REFRESH COMPLETE
option or create a simple materialized view.
I can not see a violation of any of the restrictions for materialized views as defined in Oracle's support document 179466.1.

You must not use ANSI join syntax, use the old Oracle join syntax. It is a bug in Oracle.
Long time ago I opened a case for this, however Oracle considers this only as lack of documentation!

From the docs:
Restrictions on Fast Refresh on Materialized Views with Joins Only
Defining queries for materialized views with joins only and no aggregates have the following restrictions on fast refresh:
All restrictions from "General Restrictions on Fast Refresh".
They cannot have GROUP BY clauses or aggregates.
Rowids of all the tables in the FROM list must appear in the SELECT list of the query.
Materialized view logs must exist with rowids for all the base tables in the FROM list of the query.

Related

How create materialized view refresh fast using where day>to_date(20200531)

full code :
create materialized view log on TABLEAU.GW_STATISTICS
WITH ROWID,
SEQUENCE(AD_ID,day)including new values;
create materialized view log on TABLEAU.GW_CLIENTS
WITH ROWID,
SEQUENCE(id,NAME)including new values;
CREATE MATERIALIZED VIEW MV_CREATIVE_DCO_ADWORDS_2
NOLOGGING
NOCOMPRESS
CACHE
NOPARALLEL
REFRESH FAST ON DEMAND
as
select TABLEAU.GW_STATISTICS.ROWID,
ACC.ROWID,
ACC.NAME,
TABLEAU.GW_STATISTICS.AD_ID,
min(TABLEAU.GW_STATISTICS.DAY),
TABLEAU.GW_STATISTICS.DAY
FROM TABLEAU.GW_STATISTICS,
TABLEAU.GW_CLIENTS ACC
WHERE TABLEAU.GW_STATISTICS.CLIENTID=ACC.ID(+) and TABLEAU.GW_STATISTICS.DAY>TO_DATE('20200531','yyyymmdd')
group by TABLEAU.GW_STATISTICS.ROWID,
ACC.ROWID,
ACC.NAME,
TABLEAU.GW_STATISTICS.AD_ID,
TABLEAU.GW_STATISTICS.DAY;
working create materialized view
WHERE TABLEAU.GW_STATISTICS.CLIENTID=ACC.ID(+)
not working create materialized view
WHERE TABLEAU.GW_STATISTICS.CLIENTID=ACC.ID(+)
AND TABLEAU.GW_STATISTICS.DAY>TO_DATE('20200531','yyyymmdd')
00000 - "cannot fast refresh materialized view %s.%s"
*Cause: Either ROWIDs of certain tables were missing in the definition or
the inner table of an outer join did not have UNIQUE constraints on
join columns.
*Action: Specify the FORCE or COMPLETE option. If this error is got
during creation, the materialized view definition may have be
changed. Refer to the documentation on materialized views.
Why cant i add a filter by date ? How to get around this limitation ?
Cause: Either ROWIDs of certain tables were missing in the definition...
For starters, you need to include the ROWID from each table in your select:
CREATE MATERIALIZED VIEW MV_CREATIVE_DCO_ADWORDS
NOLOGGING
NOCOMPRESS
CACHE
NOPARALLEL
REFRESH FAST ON DEMAND
as
select TABLEAU.GW_STATISTICS.ROWID,
ACC.ROWID,
ACC.NAME,
TABLEAU.GW_STATISTICS.AD_ID,
min(TABLEAU.GW_STATISTICS.DAY),
TABLEAU.GW_STATISTICS.DAY
FROM TABLEAU.GW_STATISTICS,
TABLEAU.GW_CLIENTS ACC
WHERE TABLEAU.GW_STATISTICS.CLIENTID=ACC.ID(+)
AND TABLEAU.GW_STATISTICS.DAY>TO_DATE('20200531','yyyymmdd')
group by TABLEAU.GW_STATISTICS.ROWID,
ACC.ROWID,
ACC.NAME,
TABLEAU.GW_STATISTICS.AD_ID,
TABLEAU.GW_STATISTICS.DAY;
or the inner table of an outer join did not have UNIQUE constraints on
join columns.
Also, TABLEAU.GW_STATISTICS.CLIENTID needs to have a unique constraint.
Maybe you need to use alias:
select
TABLEAU.GW_STATISTICS.ROWID as GW_STATISTICS_ROWID,
ACC.ROWID AS ACC_ROWID,
ACC.NAME,
TABLEAU.GW_STATISTICS.AD_ID,
min(TABLEAU.GW_STATISTICS.DAY) AS MIN_DAY,
TABLEAU.GW_STATISTICS.DAY
or try
FROM (SELECT * FROM TABLEAU.GW_STATISTICS WHERE DAY > DATE '2020-05-31') STATS,
TABLEAU.GW_CLIENTS ACC
WHERE STATS.CLIENTID = ACC.ID(+)
Should be the same, I think

materialized view with primary key not work

Goodnight,
I am having trouble creating a materialized view type primary key, the 2 tables have primary key. as follows: the table "cotizacion" has two primary keys,
-fecha
-neumatico
the table "table_hija1", has a primary key: "id"
what may be the problem, I will appreciate your help. Thanks,
obs:
-It has to be of the refresh on demand type
-table_child1, is a large table that contains data from 50 small tables. It is not possible to divide
them into 50 small tables.
CREATE MATERIALIZED VIEW LOG ON Cotizacion
WITH primary key
INCLUDING NEW VALUES;
CREATE MATERIALIZED VIEW LOG ON tabla_hija1
WITH primary key
INCLUDING NEW VALUES;
create materialized view vm_prueba3
refresh fast on demand
with primary key
as
select
c.id id1,
e.id id2,
f.id id3,o.neumatico,
o.idproceso,
o.fecha,
o.precio
from Cotizacion o, tabla_hija1 c, tabla_hija1 e,tabla_hija1 f
where
( o.estado=c.vvalor(+) and c.tipo_filtro=1 )
and
( o.segmento=e.vvalor(+) and e.tipo_filtro=2)
error:
ORA-12052: no se puede realizar un refrescamiento rĂ¡pido de la vista materializada SYSTEM.VM_PRUEBA3
00000 - "cannot fast refresh materialized view %s.%s"
*Cause: Either ROWIDs of certain tables were missing in the definition or
the inner table of an outer join did not have UNIQUE constraints on
join columns.
*Action: Specify the FORCE or COMPLETE option. If this error is got
during creation, the materialized view definition may have be
changed. Refer to the documentation on materialized views.
"ROWIDs of certain tables were missing in the definition"
From the documentation, for MVs with joins performing FAST REFRESH ON DEMAND:
A materialized view log must be present for each detail table unless
the table supports partition change tracking (PCT). Also, when a
materialized view log is required, the ROWID column must be present
in each materialized view log.
The rowids of all the detail tables must appear in the SELECT list of the materialized view query definition.
https://docs.oracle.com/en/database/oracle/oracle-database/19/dwhsg/basic-materialized-views.html#GUID-3B903558-0C98-4033-9BCD-4A146220E868
You need to include the rowids of each source table in your materialized view:
CREATE MATERIALIZED VIEW LOG ON Cotizacion
WITH rowid
INCLUDING NEW VALUES;
CREATE MATERIALIZED VIEW LOG ON tabla_hija1
WITH rowid
INCLUDING NEW VALUES;
create materialized view vm_prueba3
refresh fast on demand
with rowid
as
select
c.rowid c_rowid,
e.rowid e_rowid,
f.rowid f_rowid,
o.rowid o_rowid,
c.id id1,
e.id id2,
f.id id3,o.neumatico,
o.idproceso,
o.fecha,
o.precio
from Cotizacion o, tabla_hija1 c, tabla_hija1 e,tabla_hija1 f
where
( o.estado=c.vvalor(+) and c.tipo_filtro=1 )
and
( o.segmento=e.vvalor(+) and e.tipo_filtro=2)

How to create a materialized view with union(or union all) and joins

For performance needs I want to create a materialized view on commit refresh option using the following script:
CREATE TABLE DEVDV
(DEVDV_ID INTEGER PRIMARY kEY,
DEVDV_SRC_DVISE_ID INTEGER,
DEVDV_CIB_DVISE_ID INTEGER);
CREATE TABLE CONDV
(CONDV_ID INtEgEr PRiMARY KEY,
CONDV_DEVDV_iD INTEGER,
CONDV_TX NUMbeR,
CONDV_DATE_DEB datE,
CONDV_DATE_FIN DATE);
CREATE MATERIALIZED VIEW LOG ON DEVDV WITH ROWID;
CREATE MATERIALIZED VIEW LOG ON CONDV WITH ROWID;
CREATE MATERIALIZED VIEW MV_DEVDV_TYP_2
REFRESH FAST
ON COMMIT
AS
SELECT DEVDV.ROWID CROWID,
CONDV.ROWID DROWID,
DEVDV_ID,
1 AS MARKER,
DEVDV_SRC_DVISE_ID,
DEVDV_CIB_DVISE_ID,
CONDV_TX,
CONDV_DATE_DEB,
CONDV_DATE_FIN
FROM
DEVDV INNER JOIN CONDV ON DEVDV_ID = CONDV_DEVDV_ID
UNION ALL
SELECT DEVDV.ROWID CROWID,
CONDV.ROWID DROW_ID,
DEVDV_ID,
2 AS MARKER,
DEVDV_CIB_DVISE_ID,
DEVDV_SRC_DVISE_ID,
1/CONDV_TX,
CONDV_DATE_DEB,
CONDV_DATE_FIN
FROM
DEVDV INNER JOIN CONDV ON DEVDV_ID = CONDV_DEVDV_ID;
Oracle says that it's a complex query and it doesn't meet the fast refresh requirements,
Could you please tell me which rule I've broken?
I don't know why, but - for materialized views in oracle - you have to use old syntax for joins. So put all tables in FROM separating them with commas, and join condition put in where clause (use "(+)" for outer joins).
That works for me:
CREATE MATERIALIZED VIEW MV_DEVDV_TYP_2
REFRESH FAST
ON COMMIT
AS
SELECT DEVDV.ROWID CROWID,
CONDV.ROWID DROWID,
DEVDV_ID,
1 AS MARKER,
DEVDV_SRC_DVISE_ID,
DEVDV_CIB_DVISE_ID,
CONDV_TX,
CONDV_DATE_DEB,
CONDV_DATE_FIN
FROM
DEVDV, CONDV
WHERE DEVDV_ID = CONDV_DEVDV_ID
UNION ALL
SELECT DEVDV.ROWID CROWID,
CONDV.ROWID DROW_ID,
DEVDV_ID,
2 AS MARKER,
DEVDV_CIB_DVISE_ID,
DEVDV_SRC_DVISE_ID,
1/CONDV_TX,
CONDV_DATE_DEB,
CONDV_DATE_FIN
FROM
DEVDV, CONDV
WHERE DEVDV_ID = CONDV_DEVDV_ID;
Materialized view MV_DEVDV_TYP_2 created.

Materialized view data doesn't update

I want to create a materialized view with fast refresh. The view aggregates values from a single table:
CREATE TABLE N_INSP_DTSEDIF_PLANTAS (
IMPORTACION_ID NUMBER(*,0) NOT NULL,
ID NUMBER(10) NOT NULL,
INSPECCION_ID NUMBER(10) NOT NULL,
NOMBRE_PLANTA VARCHAR2(255 CHAR),
NUM_VIVIENDAS NUMBER(10),
SUP_CONSTRUIDA_VIVIENDAS DECIMAL(10,4),
-- Plus some other columns I don't need
CONSTRAINT N_INSP_DTSEDIF_PLANTAS_P PRIMARY KEY (
IMPORTACION_ID,
ID
) ENABLE,
CONSTRAINT N_INSP_DTSEDIF_PLANTAS_F FOREIGN KEY (IMPORTACION_ID)
REFERENCES IMPORTACION (IMPORTACION_ID)
ON DELETE CASCADE
ENABLE
);
CREATE INDEX N_INSP_DTSEDIF_PLANTAS_X ON N_INSP_DTSEDIF_PLANTAS (IMPORTACION_ID);
CREATE SEQUENCE N_INSP_DTSEDIF_PLANTAS_S
INCREMENT BY 1
START WITH 1
MINVALUE 1
CACHE 20;
CREATE OR REPLACE TRIGGER N_INSP_DTSEDIF_PLANTAS_T
BEFORE INSERT
ON N_INSP_DTSEDIF_PLANTAS
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
IF :NEW.ID IS NULL THEN
SELECT N_INSP_DTSEDIF_PLANTAS_S.NEXTVAL INTO :NEW.ID FROM DUAL;
END IF;
END N_INSP_DTSEDIF_PLANTAS_T;
/
ALTER TRIGGER N_INSP_DTSEDIF_PLANTAS_T ENABLE;
I've composed this through trial and error:
CREATE MATERIALIZED VIEW LOG ON N_INSP_DTSEDIF_PLANTAS
WITH ROWID, SEQUENCE (IMPORTACION_ID, INSPECCION_ID, NUM_VIVIENDAS, SUP_CONSTRUIDA_VIVIENDAS)
INCLUDING NEW VALUES;
CREATE MATERIALIZED VIEW V_PLANTAS
REFRESH FAST
AS
SELECT IMPORTACION_ID, INSPECCION_ID,
SUM(NUM_VIVIENDAS) AS NUM_VIVIENDAS, SUM(SUP_CONSTRUIDA_VIVIENDAS) AS SUP_CONSTRUIDA_VIVIENDAS
FROM N_INSP_DTSEDIF_PLANTAS
GROUP BY IMPORTACION_ID, INSPECCION_ID;
Objects get created without errors and SELECT * FROM V_PLANTAS returns data. However, the view is stalled. New rows added to N_INSP_DTSEDIF_PLANTAS don't show up at V_PLANTAS.
What did I misunderstand from the documentation?
In the mess of random changes that follow panic and despair I inadvertently dropped the ON COMMIT clause:
CREATE MATERIALIZED VIEW V_PLANTAS
REFRESH FAST ON COMMIT
AS
-- ...
The log itself is also invalid for fast refresh because I also omitted the PRIMARY KEY clause. It should be like:
CREATE MATERIALIZED VIEW LOG ON N_INSP_DTSEDIF_PLANTAS
WITH ROWID, PRIMARY KEY, SEQUENCE (INSPECCION_ID, NUM_VIVIENDAS, SUP_CONSTRUIDA_VIVIENDAS)
INCLUDING NEW VALUES;
(Said that, it's worth noting that materialized tables are not just a simple results cache but a fairly large and complex feature that requires careful planning and maintenance. In many situations is easier to just optimize the underlying query.)

Does updating a view affects the base table?

When I updated a view which was created using a base table, the updation affected the base table as well. How is that possible? If view is considered as just a 'window' through which we can see a set of data of the base table then how can the base table change when I try to change the data inside a view.
You can make changes to the state of underlying table using the view as long as the you are targeting the change in single table.
View is a security layer on top of table object and allows most of the DML operation as long as you do not violet the base rule.
Example:
CREATE TABLE T1
(ID INT IDENTITY(1,1), [Value] NVARCHAR(50))
CREATE TABLE T2
(ID INT IDENTITY(1,1), [Value] NVARCHAR(50))
--Dummy Insert
INSERT INTO T1 VALUES ('TestT1')
INSERT INTO T2 VALUES ('TestT2')
--Create View
CREATE VIEW V1
AS
SELECT T1.ID AS T1ID, T2.ID AS T2ID, T1.Value AS T1Value, T2.Value AS T2Value FROM T1 INNER JOIN T2
ON T2.ID = T1.ID
--Check the result
SELECT * FROM V1
--Insert is possible via view as long as it affects only one table
INSERT INTO V1 (T1Value) VALUES
('TestT1_T1')
INSERT INTO V1 (T2Value) VALUES
('TestT2_T2')
--Change is possible only if target is only one table
UPDATE V1
SET T1Value = 'Changed'--**
WHERE T2ID = 1
--This is not allowed
INSERT INTO V1 (T1Value, T2Value) VALUES
('TestT1_T1','TestT2_T2')
--Msg 4405, Level 16, State 1, Line 1
--View or function 'V1' is not updatable because the modification affects multiple base tables.
--Check T1 and T2 with each statement to see how it gets affected
--
In some databases it's possible to update the source table(s) for a view if there is a one-to-one relationship between the rows in the view and the rows in the underlying table, that is, you cant have derived columns, aggregate functions or a distinct clause in your view for example.
In Oracle, even if a view is not inherently updatable, updates may be allowed if an INSTEAD OF DML trigger is defined.
If you use mysql, you can read a detailed description about this feature Updatable and insertable views.
" If view is considered as just a 'window' through which we can see a set of data of the base table "
- Where did you get this definition?
What oracle says about views:
A view is a logical representation of another table or combination of
tables. A view derives its data from the tables on which it is based.
These tables are called base tables. Base tables might in turn be
actual tables or might be views themselves. All operations performed
on a view actually affect the base table of the view. You can use
views in almost the same way as tables. You can query, update, insert
into, and delete from views, just as you can standard tables.
Such a view into which you can update or insert are fondly named as "Updatable and Insertable Views". Oracle documentation about them is here.
Also, this is how the purpose of an "insert" statement is defined by Oracle:
Use the INSERT statement to add rows to a table, the base table of a
view, a partition of a partitioned table or a subpartition of a
composite-partitioned table, or an object table or the base table of
an object view.
Yes we can achieve the DML Operation in Views like belows:
Create or replace view emp_dept_join as Select d.department_id,
d.department_name, e.first_name, e.last_name from employees
e, departments d where e.department_id = d.department_id;
SQL>CREATE OR REPLACE TRIGGER insert_emp_dept
INSTEAD OF INSERT ON emp_dept_join DECLARE v_department_id departments.department_id%TYPE;
BEGIN
BEGIN
SELECT department_id INTO v_department_id
FROM departments
WHERE department_id = :new.department_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO departments (department_id, department_name)
VALUES (dept_sequence.nextval, :new.department_name)
RETURNING ID INTO v_department_id;
END;
INSERT INTO employees (employee_id, first_name, last_name, department_id)
VALUES(emp_sequence.nextval, :new.first_name, :new.last_name, v_department_id);
END insert_emp_dept;
/
if the viwe is defined through a simple query involving single base relation and either containing primary key or candidate key, so there will be change in base relation if changing the view. ( however there is restriction)
And updates are not allowed through view if there is multiple base relations or grouping operations.

Resources