I created a materialized view as show below:
CREATE MATERIALIZED VIEW ORA2ORA_DW.INVOICE_AGG
BUILD IMMEDIATE
REFRESH FORCE
ON DEMAND
DISABLE QUERY REWRITE
AS
SELECT C.CUSTOMERID , C.CUSTOMERNAME, SUM(I.QUANTITY) AS QUANTITY, MAX(I.UNITPRICE) AS UNITPRICE, MIN(I.TAXAMOUNT) AS AMOUNT,
AVG(I.TAXRATE) AS TAX, VARIANCE(I.LINEPROFIT)AS LINEPROFIT_VAR, STDDEV(I.LINEPROFIT) AS LINEPROFIT_STDEV, COUNT(I.INVOICELINESKEY) AS ROW_COUNT
FROM ORA2ORA_DW.INVOICELINES I, ORA2ORA_DW.CUSTOMERS C
WHERE I.CUSTOMERSKEY=C.CUSTOMERSKEY
GROUP BY C.CUSTOMERID , C.CUSTOMERNAME
ORDER BY C.CUSTOMERID;
but when I try to refresh it using this command "EXEC DBMS_MVIEW.REFRESH('INVOICE_AGG');", it gives me this error: ORA-00900: invalid SQL statement
Related
I want to create m-view which keeps the aggregates of cash from transaction history.
The query is as follows.
CREATE MATERIALIZED VIEW MV_CASH_STATS
BUILD IMMEDIATE REFRESH FAST ON DEMAND
AS
( -- Total aggregates
SELECT
'total' AS CODE
, COUNT(T.CASH_IN) AS DEPOSITS
, COUNT(T.CASH_OUT) AS WITHDRAWS
, SUM(T.CASH_IN) AS DEPOSIT
, SUM(T.CASH_OUT) AS WITHDRAW
FROM
TB_CASH_LOG T
)
UNION ALL
( -- Aggregates by account grades
SELECT
'grade-' || T1.GRADE AS CODE
, COUNT(T.CASH_IN) AS DEPOSITS
, COUNT(T.CASH_OUT) AS WITHDRAWS
, SUM(T.CASH_IN) AS DEPOSIT
, SUM(T.CASH_OUT) AS WITHDRAW
FROM
TB_CASH_LOG T
INNER JOIN TB_ACCOUNT T1 ON
T.ACCOUNT_ID = T1.ID
GROUP BY T1.GRADE
)
When i execute this, the following error occurs.
> ORA-12015: cannot create a fast refresh materialized view from a complex query
(I created m-view log tables for both TB_CASH_LOG and TB_ACCOUNT)
The Total aggregates part is ok, but the later part - Aggregates by account grades - makes the error.
I've read Oracle basic materialized view docs, and thinking that INNER JOIN or GROUP BY is the error point.
If it is true, fast refresh m-view with inner join and group by is impossible?
What is wrong with my m-view declaration sql?
p.s. I'm working on oracle 18c
I'm trying to implement Oracle triggers for child views but I need to be able to join the child views to their parents in order to do a role permission check.
In SQL Server I'm able to stuff like this:
ALTER TRIGGER [dbo].[ASetTrt_I] ON [dbo].[UCV_ASet_TRT]
INSTEAD OF Insert AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (SELECT 1 from INSERTED i INNER JOIN [Analysis_Sets] p on i.[key] = p.[ID]
WHERE ([dbo].IsMemberOf(p.[UpdateRole]) <> 1 and [dbo].IsMemberOf('db_owner') <> 1))
RAISERROR ('Update failed due to insufficient permission',11,1)
INSERT INTO [Set_Trts] ( [ID], [Name], [key], [f_lTreatmentKey], [f_lOrder] )
SELECT
inserted.[ID], inserted.[Name], inserted.[key], inserted.[f_lTreatmentKey], inserted.[f_lOrder]
FROM inserted
INNER JOIN [Sets] parentT
on inserted.[key] = parentT.[ID]
WHERE (([dbo].IsMemberOf('db_owner')=1) or ([dbo].IsMemberOf(parentT.[UpdateRole])=1))
END
Is there anything I can do in Oracle to replicate the join functionality?
I've tried selecting from :New the way that SS selects from inserted but that doesn't seem to work..
Thanks.
You don't need to join. The:new pseudorow is just available and can be referenced like a record type. It isn't a table-like structure, and is only available in a for each row trigger. So your insert would be something like:
INSERT INTO Analysis_Set_Trts ( ID, Name, f_lAnalysisSetKey, f_lTreatmentKey,
f_lOrder )
SELECT :new.ID, :new.Name, :new.f_lAnalysisSetKey, :new.f_lTreatmentKey,
:new.f_lOrder
FROM Analysis_Sets parentT
WHERE parentT.ID = :new.f_lAnalysisSetKey
AND ((IsMemberOf('db_owner')=1) or (IsMemberOf(parentT.UpdateRole)=1));
... although not quite sure what the last line is doing or what the equivalent is.
I'm trying to create a materialized view on prebuilt table with this syntax
CREATE MATERIALIZED VIEW "STORE"
ON PREBUILT TABLE
WITH REDUCED PRECISION
REFRESH FORCE ON DEMAND
START WITH SYSDATE+4/1440
NEXT SYSDATE + 1/24
USING DEFAULT LOCAL ROLLBACK SEGMENT
DISABLE QUERY REWRITE
AS
(
(SELECT
t1.field1
t1.field2
t1.field3
t3.LAT AS LAT,
t3.LNG AS LNG,
t4.ID AS T4_ID
FROM T1#STORE_DBLINK t1
INNER JOIN T4 t4 ON t1.T4_ID = t4.ID
LEFT JOIN T3#STORE_DBLINK t3 ON t3.STORE_NUMBER = t1.NUMBER
WHERE ((t1.id = (
SELECT MAX(t2.id)
FROM T2#STORE_DBLINK t2
WHERE t2.number=t1.number
))
))
UNION
(SELECT te.field1,
te.field2,
te.field3,
te.LAT LAT,
te.LNG LNG,
te.T4_ID
FROM STORE_TMP te
WHERE STORE_NUMBER not in (select DISTINCT NUMBER from T1S#STORE_DBLINK)));
This query creates the materialized view correctly. However, when I "Edit" the materialized view via SqlDeveloper the refresh period is disabled, and the rollback segment appears like "Unspecified".
Furthermore, if I try to change Refresh "On demand" to a time period with next refresh, it nevers complete the change. The same thing happens if I execute:
ALTER MATERIALIZED VIEW STORE
REFRESH FORCE
START WITH SYSDATE+4/1440
NEXT SYSDATE+1/24;
Maybe this is due to the fact that I'm using a complex materialized view? Is there a way to fix this?
Thanks in advance.
I have two tables 'survey' & 'survey_processed' and both are basically similar tables. I have a working query which uses UNION ALL operator between two tables & am getting some counts. When I try to translate it in to a Materialized View, I get the error related to ON COMMIT. Check out the MV DDL & Error below.
CREATE MATERIALIZED VIEW vwm_survey_records_count
REFRESH FAST ON COMMIT
AS
SELECT
survey_combined.survey_header_id,
COUNT(*) AS count_total,
COUNT(CASE WHEN survey_combined.processed_flag = 'Y' THEN 1 ELSE NULL END) AS count_a,
COUNT(CASE WHEN survey_combined.approved_flag IS NULL THEN 1 ELSE NULL END) AS count_b,
COUNT(CASE WHEN survey_combined.processed_flag = 'N' AND survey_combined.approved_flag = 'Y' THEN 1 ELSE NULL END) AS count_c,
COUNT(CASE WHEN survey_combined.approved_flag = 'N' THEN 1 ELSE NULL END) AS count_d
FROM
(
SELECT survey_header_id, 'N' AS processed_flag, approved_flag FROM survey
UNION ALL
SELECT survey_header_id, 'Y' AS processed_flag, approved_flag FROM survey_processed) survey_combined
INNER JOIN survey_header ON survey_combined.survey_header_id = survey_header.id
GROUP BY survey_combined.survey_header_id;
Error I get if i run the above command:
'SQL Error: ORA-12054: cannot set the ON COMMIT refresh attribute for the materialized view' .
But, if i use the 'REFRESH COMPLETE ON DEMAND' it works. I know am obviously breaking some restrictions for the ON COMMIT attribute, but can't figure out which. Can someone let me know what am doing wrong on the above query? Also, Is there any better approach for the query as such to make it efficient & work with 'REFRESH FAST ON COMMIT', while creating the MV.
Note: I have the MV Log created for both the tables using rowid on the selected columns.
Let me know if someone has any questions.
Thanks in advance.
Here's the DDL for MV Log as requested by 'jonearles'
CREATE MATERIALIZED VIEW LOG ON survey WITH SEQUENCE,ROWID (id, survey_header_id, approved_flag, processed_flag) INCLUDING NEW VALUES;
CREATE MATERIALIZED VIEW LOG ON survey_processed WITH SEQUENCE,ROWID (id, survey_header_id, approved_flag) INCLUDING NEW VALUES;
CREATE MATERIALIZED VIEW LOG ON survey_header WITH SEQUENCE,ROWID (id) INCLUDING NEW VALUES;
Note: The column 'processed_flag' in the 'survey' table will be dropped later on. Technically, the two tables were recently split based on the value of the 'processed_flag' column. So, the 'survey' table has all the un-processed records (processed_flag = 'N') & 'survey_processed' has the processed records (processed_flag = 'Y'). After the split, the column is irrelevant.
I think you're out of luck here. From Restrictions on Fast Refresh on Materialized Views with UNION ALL:
The defining query must have the UNION ALL operator at the top level.
And replacing the UNION ALL with outer joins doesn't work either. Aggregation and outer joins don't appear to work together. The code below is not equivalent to yours, but it demonstrates that even a much simplified version of your query won't work:
CREATE MATERIALIZED VIEW vwm_survey_records_count
REFRESH COMPLETE ON DEMAND AS
SELECT survey_header.id AS survey_header_id, COUNT(*) AS count_total
FROM survey_header, survey, survey_processed
WHERE survey_header.id = survey.survey_header_id(+)
GROUP BY survey_header.id;
delete from MV_CAPABILITIES_TABLE;
begin
DBMS_MVIEW.EXPLAIN_MVIEW ('VWM_SURVEY_RECORDS_COUNT');
end;
/
select possible, msgno, msgtxt
from MV_CAPABILITIES_TABLE
where capability_name = 'REFRESH_FAST_AFTER_INSERT';
POSSIBLE MSGNO MSGTXT
-------- ----- ------
N 2048 outer join in mv
I have a problem while creating views with a procedure, because the Oracle ignores the order of columns I specified.
I create the text of the command for creating view in a loop (in every loop one view), at the end of view I execute EXECUTE IMMEDIATE textOfCommand;
I tried to add /*+ORDERED */ before select but this did not help. (I also tried to run the queries directly, not from procedure)
The generated command itself is good, also column_id is good, but it is ignored in oracle developer or in geomedia. I think this will be something with optimization of the query, because there are several joins in the query.
I just cannot understand why it is so unpredictable, The order is sometimes good, sometimes not (if I run the same command several times) it doesn't depend on view, it is absolutely random, and I cannot figure out what is the reason.
If you have any idea, please share it. Thanks
EDIT :
I have a problem with the order of columns (not rows) that are shown in oracle developer and also geomedia. When I click the tab 'Columns' in Oracle developer, a can see all the columns of view with good COLUMN_ID, but they are not ordered by this column. I thought it was just the way, that the oracle developer displays it, but also other software has a problem with it. If I run the select command, the order is good. I wouldn't mind the order in oracle developer, but the problem is the customer's software (geomedia).
here is an examle of generated sql that is created by procedure and then run by EXECUTE IMMEDIATE command at the end of each loop in procedure. :
(there is something about 100 such a views. Tables, columns and orders is taken from one configuration table, that specifies all this. And I use GDOSYS.GPICKLISTS to identify FK and tables that should be joined)
CREATE OR REPLACE FORCE VIEW "SOME_VIEW" AS
SELECT /*+ORDERED */ a.ID AS "ID",
a8.TEXT_EN AS "COLUMN_NAME_1",
a.COLUMN_NAME_2 AS "COLUMN_NAME_2",
a.COLUMN_NAME_3 AS "COLUMN_NAME_3",
to_char(a.COLUMN_NAME_4,'yyyymmdd') AS "COLUMN_NAME_4",
to_char(a.COLUMN_NAME_5,'yyyymmdd') AS "COLUMN_NAME_5",
to_char(a.COLUMN_NAME_6,'yyyymmdd') AS "COLUMN_NAME_6",
to_char(a.COLUMN_NAME_7,'yyyymmdd') AS "COLUMN_NAME_7",
a.COLUMN_NAME_8 AS "COLUMN_NAME_8",
a.COLUMN_NAME_9 AS "COLUMN_NAME_9",
a.COLUMN_NAME_10 AS "COLUMN_NAME_10",
to_char(a.COLUMN_NAME_11,'yyyymmdd') AS "COLUMN_NAME_11",
a9.TEXT_EN AS "COLUMN_NAME_12",
a10.TEXT_EN AS "COLUMN_NAME_13",
a.COLUMN_NAME_14 AS "COLUMN_NAME_14",
a11.TEXT_EN AS "COLUMN_NAME_15",
FROM SOME_TABLE a
LEFT JOIN IENC.TABLE1 a8 on a8.id = a.COLUMN_NAME_1
LEFT JOIN IENC.TABLE2 a9 on a9.id = a.COLUMN_NAME_12
LEFT JOIN IENC.TABLE3 a10 on a10.id = a.COLUMN_NAME_13
LEFT JOIN IENC.TABLE4 a11 on a11.id = a.COLUMN_NAME_15
I assume what is "unpredictable" is something like
SELECT column_name, data_type, column_id
FROM user_tab_cols
WHERE table_name = 'SOME_VIEW';
If you want to order rows by some column, you must explicitly add ORDER BY clause.
SELECT column_name, data_type, column_id
FROM user_tab_cols
WHERE table_name = 'SOME_VIEW'
ORDER BY column_id;
Try without the double quote for the columns' name.
SELECT /*+ORDERED */ a.ID AS "ID", => SELECT /*+ORDERED */ a.ID AS ID,