oracle materialized view refresh time - oracle

anyone able to tell me how often a materialized view is set to refresh with the following setting plz?
REFRESH FORCE ON DEMAND START WITH sysdate+0 NEXT (round(sysdate) + 1/24) + 1
i think i read it as every hour but i'm not sure

SQL> alter session set nls_date_format = 'yyyy-mm-dd :hh24:mi:ss';
Session changed.
SQL> select sysdate from dual;
SYSDATE
--------------------
2008-12-19 :12:18:28
SQL> select (round(sysdate) + 1/24) + 1 from dual;
(ROUND(SYSDATE)+1/24
--------------------
2008-12-21 :01:00:00

To answer your first question (will this run once an hour?):
Nope, this will run once when you create it because of this clause:
START WITH sysdate+0
Personally, I think the "+0" is extraneous, as now is now.
Then it will run tomorrow at 1 a.m., because of the following clause:
NEXT (round(sysdate) + 1/24) + 1
The "1/24" part calculates when 1 a.m. is, since Oracle dates are actually stored as numbers, with the decimal part indicating hours, minutes, etc. The syntax is just fine.

I'm not 100% sure that it's legal in a materialized view scheduling statement, but you might like to try the (arguably) more intuitive INTERVAL specification:
round(sysdate) + interval '1 1' day to hour
Other examples here: http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements003.htm#SQLRF00221

i think using
NEXT (trunc(sysdate) + 1/24) + 1
is more accurate

Related

Create TimeStamp with fixed Time Part

What's the best way to get a timestamp that consists of the actual date but a fixed time part in oracle.
e.g.Today and always 09:00:00
2020-10-20 09:00:00
in MSSQL I would use FORMAT(GETDATE(),'yyyy-MM-dd 09:00:00')
Assuming you want a date rather than a varchar2, I'd use
trunc(sysdate) + interval '9' hour
trunc(sysdate) returns today at midnight and then interval '9' hour adds 9 hours to give you 9am. You can also add fractions of a day to a date so you could say
trunc(sysdate) + 9/24
I tend to find the interval notation more self-explanatory particularly if you're coming from a non-Oracle background.
You can use something like this:
SQL> alter session set NLS_DATE_FORMAT='YYYY-MM-DD';
Session altered.
SQL> set head off
SQL> select sysdate||' 09:00:00' from dual;
2020-10-19 09:00:00
Hope this is what you were looking for :)

Date operations in Oracle

I'm trying to run this queries (Oracle 12c):
SELECT trunc(sysdate) - '25-SEP-18' FROM dual;
SELECT 1 FROM dual WHERE trunc(sysdate) = '04-SEP-19';
CREATE TABLE my_table (order_date date);
INSERT INTO my_table (order_date) VALUES ('04-SEP-19');
I expect implicit conversion and everything is good with the 2 last queries, but for the first i get error ORA-01722: invalid number. NLS_DATE_FORMAT = 'DD-MON-RR'. What is the problem?
The question is WHY is does not work? I didn't find any explanations in documentation.
The documentation has a section on Datetime/Interval Arithmetic which explains what is allowed. The table shows that arithmetic is only allowed between dates, timestamp, intervals and numbers. When you do:
SELECT trunc(sysdate) - '25-SEP-18'
you are trying to subtract a string from a date, which isn't possible. Oracle 'helpfully' tries anyway and interprets the string as a number, effectively doing:
SELECT trunc(sysdate) - to_number('25-SEP-18')
which understandably throws the error you see, "ORA-01722: invalid number". As already said, you should explicitly convert your string to a date:
SELECT trunc(sysdate) - to_number('25-SEP-18', 'DD-MON-RR')
or preferably with a four-digit year, and since you're using a month name it's safer to specify the language that is in:
SELECT trunc(sysdate) - to_number('25-SEP-2018', 'DD-MON-YYYY', 'NLS_DATE_LANGUAGE=ENGLISH')
or more simply, if it's a fixed value, with a date literal:
SELECT trunc(sysdate) - DATE '2018-09-25'
I expect implicit conversion
You should not rely on implicit conversion, particularly where that is influenced by session NLS settins. As well as the date language I already mentioned, someone else running your statement could have a different NLS_DATE_FORMAT setting which could lead to errors or more subtle data mismatches or corruption; e.g.
alter session set nls_date_format = 'DD-MON-YYYY';
SELECT trunc(sysdate) - DATE '2018-09-25' FROM dual;
TRUNC(SYSDATE)-DATE'2018-09-25'
-------------------------------
344
SELECT trunc(sysdate) - to_date('25-SEP-18') FROM dual;
TRUNC(SYSDATE)-TO_DATE('25-SEP-18')
-----------------------------------
730831
SELECT 1 FROM dual WHERE trunc(sysdate) = '04-SEP-19';
no rows selected
CREATE TABLE my_table (order_date date);
INSERT INTO my_table (order_date) VALUES ('04-SEP-19');
The second query gets a much bigger value than expected; and the third gets no rows back from dual.
Looking at the implicitly converted date shows you why:
SELECT to_char(order_date, 'SYYYY-MM-DD HH24:MI:SS') FROM my_table;
TO_CHAR(ORDER_DATE,'
--------------------
0019-09-04 00:00:00
With a YYYY mask (and no FX modifier) a 2-digit year value like 19 is converted as 0019, not 2019. That sort of problem could go unnoticed for some time, giving you incorrect results in the meantime.
If the session's format mask had RRRR or - as you have - RR then it would be interpreted as 2019; but the point is that you usually have no control over the settings in another session that runs your code later.
You can also cause performance issues or errors by creating implicit conversions where you didn't expect, or where they behave in a way you didn't expect. Not in this example - "When comparing a character value with a DATE value, Oracle converts the character data to DATE" - but it still comes up. It's better to avoid the possibility.
When dealing with strings with dates in them you should use the to TO_DATE command, otherwise Oracle may not always figure out that the string contains a date.
SELECT trunc(sysdate) - TO_DATE('25-SEP-18') FROM dual;
Even better is to indicate the format of the date within the string
SELECT trunc(sysdate) - TO_DATE('25-SEP-18','DD-MON-RR') FROM dual;

How to compare dates in a PL/SQL procedure?

I'm a newbie in SQL programming.
I need to make a procedure that will compare dates. The only argument in the procedure is a date typed in by the user in a Java program. I need to check if that argument (date) is before a year ago. In other words, I need to compare it with SYSDATE minus a year. If that is the case, I have to "purge" all of the tables related to "schedules" (there are 2 of them).
So for example, say the user types 2013-04-13, my procedure has to compare it with SYSDATE - 1 year (in that case, it would be 2014-12-03). Since the value is less than today minus a year, the tables "MovieSchedule" and "ChannelSchedule" have to be purged. If the entered date was 2014-12-16, since it's now more than SYSDATE minus a year, the procedure has to send back an explicit error that I will be able to use in the Java program.
Now, as I said I'm completely new to procedure programming in PL/SQL, so here is what I could come up with by looking up tutorials on the internet:
CREATE OR REPLACE
PROCEDURE purge_schedule(purgeDate date) AS
DECLARE
currentDate := to_date(SYSDATE, 'YYYMMDD');
BEGIN
-- IF purgeDate < (currentDate - 1year)
-- delete content in "MovieSchedule" and "ChannelSchedule"
-- ELSE
-- return explicit error
END purge_schedule;
I don't even know if any of this is the right way to write a procedure like I want. And as you can see, my problem is how to implement my condition in the procedure, not the logic behind it. I blame my lack of practice with the language.
Please tell me if I have to be more specific of if you need more information in order to help me. Thank you for your help and have a nice day :)
Step 1, define year. Should be obvious, but is not. I have found month and year definitions vary in the wild. I've seen year defined as 52 weeks, which is never an actual year, and 365 days, which matches one year a little less than 3 of every 4 years, and occasionally 360 days! (30 days / month * 12 months)
sysdate - 365 gives a date 365 days ago.
ADD_MONTHS(sysdate, -12) will give the date 12 months ago. In the case that sysdate is February 29, the result will be February 28 of the prior year.
sysdate - interval '1' year is tempting, but interval year to month arithmetic throws errors when the "result" is a day that is not there.
select date '2012-02-28' - interval '1' year from dual;
02/28/2011
select date '2012-02-29' - interval '1' year from dual;
ORA-01839: date not valid for month specified
It should fill your needs:
IF purgeDate < SYSDATE -365 THEN
...
END IF;
I have illustrated a below working code which help you. Let me know if this helps.
--Compiling the stored proc
CREATE OR REPLACE PROCEDURE purge_schedule(
purgeDate IN DATE )
AS
currentDate DATE:=SYSDATE;
BEGIN
IF purgeDate < ADD_MONTHS(SYSDATE,-12) THEN
DELETE FROM EMP;
DELETE FROM EMP_V1;
dbms_output.put_line('Records purged successfully');
ELSE
RAISE_APPLICATION_ERROR(-20001,'Date provided is not in range deletion not invoked',TRUE);
END IF;
END purge_schedule;
-- Exceuting the proc
set serveroutput on;
exec purge_schedule(to_date('12/12/2013','MM/DD/YYYY'));
-- Output
Records purged successfully
--Executing for negative scenario
set serveroutput on;
exec purge_schedule(TO_DATE('12/12/2017','MM/DD/YYYY'));
--Explicit exception raise
exec purge_schedule(TO_DATE('12/12/2017','MM/DD/YYYY'));
Error report -
ORA-20001: Date provided is not in range deletion not invoked
ORA-06512: at "AVROY.PURGE_SCHEDULE", line 11
ORA-06512: at line 1

Create Materialized view which refresh records on daily

Currently the Materialized view which I had created using REFRESH ON DEMAND so in this case I need to refresh MV explicitly using below command:
BEGIN DBMS_MVIEW.REFRESH('MV_DATA'); END;
But now I need to refresh this MV on daily basis so could anyone please help to write this. I have seen that we can refresh this MV using writing explicit Job or using COMPLETE/FAST REFRESH statement in MV itself.
Thanks in advance!
You need to create the materialized view using START WITH and NEXT Clause
create materialized view <mview_name>
refresh on demand
start with sysdate next sysdate + 1
as select ............
So if you want to refresh mview daily, you need to keep it refresh on demand and set the next refresh time as sysdate + 1. You can set any interval although.
Once you do this the materialized view is created and a job is set in Oracle that will refresh mview every 24 hrs (sysdate + 1).
For more information on how to do that, follow this link
If you simply need a SQL query to simply refresh at 12 AM, then the below query would be enough.
CREATE MATERIALIZED VIEW MV_DATA
BUILD IMMEDIATE
REFRESH FAST START WITH (SYSDATE) NEXT (SYSDATE + 1) WITH ROWID
ON COMMIT
DISABLE QUERY REWRITE
AS SELECT * FROM <YOUR TABLE>
If you need to have it refreshed around 6 AM, then use the below script. You can see and additional logic as + 6 / 24. In case if you need to change to 4 AM, use the logic as + 4 / 24.
CREATE MATERIALIZED VIEW MV_DATA
BUILD IMMEDIATE
REFRESH FAST START WITH (SYSDATE) NEXT (SYSDATE + 1) + 6 / 24 WITH ROWID
ON COMMIT
DISABLE QUERY REWRITE
AS SELECT * FROM <YOUR TABLE>
I have edited Sarath's Script for it to run on specific time (i.e. 6AM).
CREATE MATERIALIZED VIEW MV_DATA
BUILD IMMEDIATE
REFRESH FAST START WITH (SYSDATE) NEXT (TRUNC(SYSDATE) + 1) + 6 / 24 WITH ROWID
ON COMMIT
DISABLE QUERY REWRITE
AS SELECT * FROM YOURTABLE
Refresh the mv every day at 1 AM
CREATE MATERIALIZED VIEW test1
BUILD IMMEDIATE
USING INDEX
REFRESH COMPLETE ON DEMAND START WITH sysdate+0 NEXT (trunc(sysdate)+1)+1/24
USING DEFAULT LOCAL ROLLBACK SEGMENT
USING ENFORCED CONSTRAINTS DISABLE QUERY REWRITE
"Your query"

Send mail when transaction time is behind system time on UNIX

I have a query to run on oracle that gives output as sid,serial#,transaction start time,sql_id,transaction id.
What I need to do is, whenever a transaction's start time is more than 1 hour behind the system time, I need to run another query with that sql_id and send it as an email.
How do I compare this time output from ORACLE sql and compare it with the system time?
I need to automate this process and add it to the cron on UNIX.
Please help!
The function SYSDATE returns the current system date. When you subtract two dates, you get a difference measured in days. Multiply by 24 and you get a difference in terms of hours.
SELECT *
FROM v$transaction
WHERE (sysdate - start_date)*24 > 1
will give you the transactions that started more than 1 hour ago. You can also use interval arithmetic if you find that clearer.
SELECT *
FROM v$transaction
WHERE sysdate - interval '1' hour > start_date

Resources