REFERENCING NEW TABLE AS is throwing invalid references in sql - oracle

Consider a view branch_cust defined as follows:
Create view branch_cust as
select
branch_name,
customer_name
from depositor, account
where depositor.account_number = account.account_number
suppose that a view is materialized; that is the view is computed and stored. Write a trigger to maintain the view, that is, to keep it up-to-date on insertions to and deletions from depositor or account. Do not bother about updates.
I tried doing an insert trigger on depositor using referencing new table as
But it is throwing errors.
This is the code.
create or replace trigger insert_dep
after insert on depositor REFERENCING NEW TABLE as inserted
FOR EACH ROW BEGIN
insert into branch_cust select branchname, cusname
from inserted, account
where inserted.account = account.acc; end;

Question is not clear, is branch_cust a table or view or materialized view ??
I will try to answer for all 3 cases :
branch_cust is view : and looking at the given DDL by you its a complex view, which means DMLs on it will fail. Also, since you are inserting into branch_cust(which is formed from table depositor) using a trigger which is also upon depositor you will get mutating error even if you make the view Simple.
so, this scenario will never work out.
branch_cust is materialized view : you cannot perform insert into a materialized view. so, trigger will fail
branch_cust is table : this can be achieved if you want to keep a separate copy of depositor data joined by account. but i suggest not to do it.

suppose that a view is materialized
Then it makes no sense in inserting into it, as those changes would be lost anyway at the first refresh.
Therefore, as it seems that you wanted to refresh it as soon as changes are made in its source table, set it to refresh on commit. Here's an example:
SQL> create materialized view mv_emp
2 refresh complete
3 on commit
4 as
5 select deptno, sum(sal) sumsal
6 From emp
7 group by deptno;
Materialized view created.
SQL> select * from mv_emp order by deptno;
DEPTNO SUMSAL
---------- ----------
10 13750
20 10995
30 9400
SQL> update emp set sal = sal + 1 where deptno = 10;
3 rows updated.
SQL> commit;
Commit complete.
SQL> select * from mv_emp order by deptno;
DEPTNO SUMSAL
---------- ----------
10 13753 --> new value for DEPTNO = 10
20 10995
30 9400
SQL>

Related

Can we create Materialized view from view with force and editionable options in oracle?

I am new to oracle. I am using oracle database 19c. I try to create a materialized view from a view. But i get "ORA-00942" error. Does this mean a mview cannot be created from a force editionable view or it is possible to create with any additional privileges? Thanks in advance.
sql>conn kish/password
Connected.
sql>create table ds as select * from dba_source;
Table created.
sql>create or replace force editionable view "dsv" as select * from ds;
View created.
sql>create materialized view dsmv as select * from dsv;
create materialized view dsmv as select * from dsv
*
ERROR at line 1:
ORA-00942: table or view does not exist
"dsv" is different from dsv. In Oracle, never use double quotes (unless you have a really, really good reason - and this isn't one).
Remove double quotes, entirely.
SQL> create view dsv as select * from dept;
View created.
SQL> create materialized view dsmv as select * from dsv;
Materialized view created.
SQL> select * from dsmv;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL>

adding a sequence to an existing table

i created a table but i forgot to add a sequence to one of the PK, its a sequence on a form page, i just cant find anything about it, is it possible or do i have to do the form all over again.
i tried to replace the PK but it doesnt give me the option to add the sequence when creating a new one.
i searched everywhere and asked the support in chat (didn't really help since its not their job).
all i could find was this and this.
I'd suggest you to skip Apex in this matter and do the following: presume this is your table:
SQL> create table test
2 (id number constraint pk_test primary key,
3 name varchar2(20)
4 );
Table created.
This is the sequence:
SQL> create sequence myseq;
Sequence created.
As you forgot to specify PK source while creating Apex Form page, never mind - let the database handle it. How? Create a BEFORE INSERT trigger:
SQL> create or replace trigger trg_bi_test
2 before insert on test
3 for each row
4 when (new.id is null)
5 begin
6 :new.id := myseq.nextval;
7 end trg_bi_test;
8 /
Trigger created.
Let's test it: I'm inserting only the NAME (which is what your Apex Form will be doing):
SQL> insert into test (name) values ('Littlefoot');
1 row created.
What is table's contents?
SQL> select * from test;
ID NAME
---------- --------------------
1 Littlefoot
SQL>
See? Trigger automatically inserted ID (primary key) column value.
If it were an Interactive Grid (which lets you insert several records at a time):
SQL> insert into test (name)
2 select 'Bigfoot' from dual union all
3 select 'FAD' from dual;
2 rows created.
SQL> select * from test;
ID NAME
---------- --------------------
1 Littlefoot
2 Bigfoot
3 FAD
SQL>
Works just fine.
And what's another benefit: you don't have to modify Apex application at all.

Create materialised view without data

I need to create materialized view test without data then I will create a script to insert data into this materialized view for the first time. After this I will run materialized view refresh to refresh the view every night.
As I am not expert in materialized views can anyone help me here.
At present I have script to create materialized view which is running for 2 hours for 20 million rows.
create materialize view
If I understand the question correctly, you want to break up the MV creation into separate steps:
Create an empty table / materialized view.
Populate it.
Schedule a nightly refresh process.
For this you can use the on prebuilt table clause to change a normal table into a materialized view.
Demo source table:
create table demo_source (id, name) as
select 1, 'Red' from dual union all
select 2, 'Yellow' from dual union all
select 3, 'Orange' from dual union all
select 4, 'Blue' from dual;
New table which is going to be our MV (you could also populate it with the create table as select, or you could create it using explicit column names, datatypes, constraints, partitioning etc like any normal table):
create table demo_mv as
select * from demo_source s
where 1 = 2;
Populate it using a separate insert step:
insert into demo_mv
select * from demo_source;
Now we convert it from a regular table into an MV:
create materialized view demo_mv on prebuilt table
as
select * from demo_source;
Now DEMO_MV is a materialized view.
If I were you, I'd create the materialized view "as is" (i.e. no restrictions you mentioned).
Anyway: the simplest option is to include the false condition in the WHERE clause which creates the object without data, such as
SQL> create materialized view mv_dept as
2 select * from dept
3 where 1 = 2; --> this
Materialized view created.
SQL> select * from mv_dept;
no rows selected
SQL> desc mv_dept;
Name Null? Type
----------------------------- -------- --------------------
DEPTNO NOT NULL NUMBER(2)
DNAME VARCHAR2(14)
LOC VARCHAR2(13)
SQL>
I know this question was asked specifically about Oracle, but I got here looking for the same question about Postgres.
Luckily, Postgres has a 'WITH NO DATA' clause at the end of the materialized view statement that just creates the view but does not populate data into it. It can still be refreshed on-demand the same way after that.
https://www.postgresql.org/docs/current/sql-creatematerializedview.html
I have the same problem. At deploy time I don't want that the refresh takes to0 much time. So here I think is a better solution.
drop materialized view test_mv;
create materialized view test_mv
as select * from all_objects
where 1 = ( select count(*) from user_tables where table_name = 'TEST_MV' ) ;
select * From test_mv
=> null
exec DBMS_MVIEW.REFRESH('TEST_MV', method => 'C', atomic_refresh => FALSE, out_of_place => false , PARALLELISM => 4);
select * From test_mv
=> result is now of all objects

Materialized Views: how can I find the number of updates, inserts, and deletes applied during refresh?

I have a data mart mastered from our OLTP Oracle database using basic Materialized Views with on demand fast refresh capability. Refresh is working fine. What I am interested in adding are some statistics about the refresh of each Materialized View, such as the number of inserts, updates, and deletes that were applied to the master table since the last refresh like that data I can find in user_tab_modifications. Is this possible for Materialized Views?
Prior to doing the refresh, you could query the materialized view log to see what sort of change vectors it stores. Those will be the change vectors that need to be applied to the materialized view during the refresh process (assuming that there is just one materialized view that depends on this materialized view log).
For example, if I create my table, my materialized view log, and my materialized view.
SQL> create table foo( col1 number primary key);
Table created.
SQL> create materialized view log on foo;
Materialized view log created.
SQL> ed
Wrote file afiedt.buf
1 create materialized view mv_foo
2 refresh fast on demand
3 as
4 select *
5* from foo
SQL> /
Materialized view created.
SQL> insert into foo values( 1 );
1 row created.
SQL> insert into foo values( 2 );
1 row created.
SQL> commit;
Commit complete.
Now, I refresh the materialized view and verify that the table and the materialized view are in sync
SQL> exec dbms_mview.refresh( 'MV_FOO' );
PL/SQL procedure successfully completed.
SQL> select * from user_tab_modifications where table_name = 'MV_FOO';
no rows selected
SQL> select * from foo;
COL1
----------
1
2
SQL> select * from mv_foo;
COL1
----------
1
2
Since the two objects are in sync, the materialized view log is empty (the materialized view log will be named MLOG$_<<table name>>
SQL> select * from mlog$_foo;
no rows selected
Now, if I insert a new row into the table, I'll see a row in the materialized view log with a DMLTYPE$$ of I indicating an INSERT
SQL> insert into foo values( 3 );
1 row created.
SQL> select * from mlog$_foo;
COL1 SNAPTIME$ D O
---------- --------- - -
CHANGE_VECTOR$$
--------------------------------------------------------------------------------
XID$$
----------
3 01-JAN-00 I N
FE
2.2519E+15
So you could do something like this to get the number of pending inserts, updates, and deletes.
SELECT SUM( CASE WHEN dmltype$$ = 'I' THEN 1 ELSE 0 END ) num_pending_inserts,
SUM( CASE WHEN dmltype$$ = 'U' THEN 1 ELSE 0 END ) num_pending_updates,
SUM( CASE WHEN dmltype$$ = 'D' THEN 1 ELSE 0 END ) num_pending_deletes
FROM mlog$_foo
Once you refresh the materialized view log, however, this information is gone.
On the other hand, USER_TAB_MODIFICATIONS should track the approximate number of changes that have been made to the materialized view since the last time that statistics were gathered on it just as it would track the information for a table. You'll almost certainly need to call DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO to force the data to be made visible if you want to capture the data before and after the refresh of the materialized view.
SELECT inserts, updates, deletes
INTO l_starting_inserts,
l_starting_updates,
l_starting_deletes
FROM user_tab_modifications
WHERE table_name = 'MV_FOO';
dbms_mview.refresh( 'MV_FOO' );
dbms_stats.flush_database_monitoring_info;
SELECT inserts, updates, deletes
INTO l_ending_inserts,
l_ending_updates,
l_ending_deletes
FROM user_tab_modifications
WHERE table_name = 'MV_FOO';
l_incremental_inserts := l_ending_inserts - l_starting_inserts;
l_incremental_updates := l_ending_updates - l_starting_updates;
l_incremental_deletes := l_ending_deletes - l_starting_deletes;

Oracle SEQUENCE.Currval problem in CodeIgniter

I have a sequence named WCOMP_SEQ in oracle to generate auto increment column ON WCOMP table. When I insert a row to WCOMP table in SQLPlus, the row inserted and I can get the auto increment value using
SELECT WCOMP_SEQ.currval FROM dual
But when I ran insert a row using Database Class in CodeIgniter, the row inserted but when I ran the query above to get auto increment value I got Exception:
Exception: Undefined Index currval in E:...
How to fix this?
There is a way to get the value automatically assigned to a column: it is the RETURNING clause.
So, here is my sequence:
SQL> select emp_seq.currval from dual
2 /
CURRVAL
----------
8140
SQL>
I'm going to use it in an INSERT statement:
SQL> var seqval number
SQL> insert into emp
2 (empno, ename, deptno, sal, job)
3 values
4 (emp_seq.nextval, 'JELLEMA', 50, 4575, 'PAINTER')
5 returning empno into :seqval
6 /
1 row created.
SQL>
I returned the EMPNO into a SQL*Plus variable which I can print, and it has the same value as CURRVAL:
SQL> print :seqval
SEQVAL
----------
8141
SQL> select emp_seq.currval from dual
2 /
CURRVAL
----------
8141
SQL>
Your next question is, "does CodeIgniter support the RETURNING sysntax?" I have no idea, but I suspect it does not. Most non-Oracle frameworks don't.
There is always the option to wrap the INSERT statement in a stored procedure, but that's an architectural decision whoch many people dislike.
You can not fetch the SEQUENCE current value without issuing NEXTVAL (see here). So, if you do not want to increment the sequence value (by using NEXTVAL), you should instead query USER_SEQUENCES.
Something like this:
select Sequence_Name
, Last_Number
from user_sequences
where sequence_name = 'WCOMP_SEQ'
/
SEQUENCE_NAME LAST_NUMBER
------------- -----------
WCOMP_SEQ 20
Hope this helps.
In order to get currval on the sequence you will need to have at least one reference to the corresponding nextval for the sequence in the current user session. This is what causes it to set the currval value which would belong to the session.
If you are using it outside, it defeats the purpose which value could it return if there were other sessions active.

Resources