How can I add a date with integer - sql

In PostgreSQL we have two tables:
a table is called:"users" and it contains the information from members like user_id and acc_type_id which is integer and shows the number of months that an account would be expired and it contains expiry_date (timestamp) which shows the time that the account will be expired
We have another table "account_type" which contains account_type_id and validity which is integer(the number of months)
Now when a user fill “users table” I want to put a trigger on insert and update:
When the user choose acc_type_id the expiry_date will be calculated automatically with the below formula:
For example today is 2020-01-06 and they choose gold account which is 9 month (I defined it integer), so their expiry_date should be: 2020-10-06 what is the best way for writing that code in short one?
declare val integer;
declare user_id_users integer:=0;
declare s integer;
BEGIN
user_id_users:=(select user_id from users where user_id=new.user_id ) ;
if ( user_id_users <> 0) then
s:=(select acc_type_id from users where user_id=new.user_id);
val:=(select validity from account_type where account_type_id=s);
update users set expiry_date= (select current_date +interval '1 month' * val where user_id=user_id_users);
end if;
return new;
END;
I have written the code for insert, but when I insert a new user, It would be in a loop and it shows a lot of similar errors continuously as below:
SQL statement "update users set expiry_date= (select current_date +interval '1 month' * val where user_id=user_id_users)" PL/pgSQL function acc_type_expiary() line 17 at SQL statement

You are over complicating things. You don't need multiple selects, you only need a single select to get the value from the account_type table. If the trigger is on the users table, there is no need to run an UPDATE.
Select the value, and assign it to the new record
DECLARE
l_months integer;
BEGIN
select at.validity
into l_months
from account_type at
where at.account_type_id = new.acc_type_id;
-- no UPDATE, just assign the value.
new.expiry_date := current_date + (interval '1 month' * l_months);
return new;
END;
Instead of (interval '1 month' * l_months) you can also use make_interval(months => l_months)
This requires that the trigger is defined as before update for each row

Looks like your update should read:
update users set expiry_date = (current_date + interval '1 month' * val) where user_id = user_id_users;

Related

Getting unexpected values for number of days between two dates in oracle

I am writing a SQL code which fetches two dates from the database and calculates the number of days between them. Here is the code:
create table borrower(
roll_no number,
date_of_issue date,
name_of_book varchar(20),
status varchar(10)
);
insert into borrower values(1,to_date('02-JAN-2022'),'dbms','issued');
insert into borrower values(2,to_date('10-JAN-2022'),'cns','issued');
insert into borrower values(3,to_date('17-JAN-2022'),'spos','issued');
insert into borrower values(4,to_date('26-JAN-2022'),'toc','issued');
create table fine(
roll_no number,
current_date date,
amount number
);
insert into fine values(1,to_date('14-FEB-2022'),null);
insert into fine values(2,to_date('14-FEB-2022'),null);
insert into fine values(3,to_date('14-FEB-2022'),null);
insert into fine values(4,to_date('14-FEB-2022'),null);
DECLARE
roll_counter number:=1;
initial_date date;
final_date date;
date_calc number;
BEGIN
loop
select date_of_issue into initial_date from borrower where roll_no=roll_counter;
select current_date into final_date from fine where roll_no=roll_counter;
date_calc:=final_date-initial_date;
dbms_output.put_line(date_calc);
roll_counter:=roll_counter+1;
exit when roll_counter>4;
end loop;
END;
/
drop table borrower;
drop table fine;
I am not getting any error, but instead getting unexpected values for the number of days. Here is the output:
Statement processed.
246.4165625
238.4165625
231.4165625
222.4165625
I was expecting the number of days between the two dates(check the table). Can someone help me sort this out.
CURRENT_DATE is an Oracle keyword that returns the current date. Name your column something that is not an Oracle keyword.
https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/CURRENT_DATE.html
As #Matthew McPeak pointed out, CURRENT_DATE is a built-in function and that function is being called rather than returning your column value.
If you want the column value then you need to prefix the column name with the table name/alias and use fine.current_date:
DECLARE
roll_counter number:=1;
initial_date date;
final_date date;
date_calc number;
BEGIN
FOR roll_counter IN 1 .. 4 LOOP
select date_of_issue
into initial_date
from borrower
where roll_no=roll_counter;
select fine.current_date
into final_date
from fine
where roll_no=roll_counter;
date_calc:=final_date-initial_date;
dbms_output.put_line(date_calc);
END LOOP;
END;
/
Which, for your sample data, outputs:
43
35
28
19
Or you can use a single query (rather than multiple queries that are called in each loop iteration):
BEGIN
FOR r IN (
SELECT f.current_date - b.date_of_issue AS diff
FROM borrower b
FULL OUTER JOIN fine f
ON (b.roll_no = f.roll_no)
WHERE COALESCE(b.roll_no, f.roll_no) BETWEEN 1 AND 4
ORDER BY COALESCE(b.roll_no, f.roll_no)
) LOOP
dbms_output.put_line(r.diff);
END LOOP;
END;
/
db<>fiddle here

How do I store date Variable in Postgres function?

So I am working to create a function that will delete the 1 month worth records from a table. The table is in postgres. As postgres does not have stored procedures I am trying to declare a function with the logic that will insert the 1 month records into a history table and then delete the records from the live table. I have the following code :
CREATE FUNCTION DeleteAndInsertTransaction(Integer)
RETURNS Void
AS $Body$
SELECT now() into saveTime;
SELECT * INTO public.hist_table
FROM (select * from public.live_table
WHERE update < ((SELECT * FROM saveTime) - ($1::text || ' months')::interval)) as sub;
delete from public.live_table
where update < ((SELECT * FROM saveTime) - ($1::text || ' months')::interval);
DROP TABLE saveTime;
$Body$
Language 'sql';
So the above code compiles fine but when I try to run it by invoking it :- DeleteAndInsertTransaction(27) it gives me an
Error: relation "savetime" does not exist and I have no clue what is going on here.
If I take out the SELECT now() into saveTime; out of the function bloc and declare it before invoking the function then it runs fine but I need to store the current date into a variable and use that as a constant for the insert and delete and this is going against a huge table and there could be significant time difference between the insert and deletes. Any pointers as to what is going on here ?
select .. into .. is the deprecated syntax for create table ... as select ... which creates a new table.
So, SELECT now() into saveTime; actually creates a new table (named savetime), and is equivalent to: create table savetime as select now(); - it's not storing something in a variable.
To store a value in a variable, you need to first declare the variable, then you can assign the value. But you can only do that in PL/pgSQL, not SQL
CREATE FUNCTION DeleteAndInsertTransaction(p_num_months integer)
returns void
as
$Body$
declare
l_now timestamp;
begin
l_now := now();
...
end;
$body$
language plpgsql;
To insert into an existing table you need
insert into public.hist_table
select *
from public.live_table.
To select the rows from the last x month, there is no need to store the current date and time in a variable to begin with. It's also easier to use make_interval() to generate an interval based on a specified unit.
You can simply use
select *
from live_table
where updated_at <= current_date - make_interval(mons => p_pum_months);
And as you don't need a variable, you can actually do all that with a language sql function.
So the function would look something like this:
CREATE FUNCTION DeleteAndInsertTransaction(p_num_months integer)
RETURNS Void
AS
$Body$
insert into public.hist_table
select *
from live_table
where updated_at < current_date - make_interval(months => p_pum_months);
delete from public.live_table
where updated_at < current_date - make_interval(months => p_pum_months);
$Body$
Language sql;
Note that the language name is an identifier and should not be quoted.
You can actually do the DELETE and INSERT in a single statement:
with deleted as (
delete from public.live_table
where updated_at <= current_date - make_interval(months => p_pum_months)
returning *
)
insert into hist_table
select *
from deleted;

PL/SQL Trigger activation on specific months

i'm a university student working on a simple database project for our DB exam. I've reached the stage of developing the dynamic constraint for the DB via PL/SQL trigger; the database applies to a oil/gas refinirey enviroment.
Here is table on which the trigger should work:
CREATE TABLE FEED(
NUMBER_STOCK NUMBER(2) CHECK(NUMBER_STOCK>0),
REACT_NAME VARCHAR(20),
PROD_LANE_NUMB NUMBER(2),
DATE_FEED DATE PRIMARY KEY,
QUANTITY NUMBER(5) NOT NULL CHECK (QUANTITY>0),
CONSTRAINT FKA FOREIGN KEY (NUMBER_STOCK) REFERENCES STOCKS(NUMBER_STOCK) ON DELETE CASCADE,
CONSTRAINT FKA2 FOREIGN KEY (REACT_NAME,PROD_LANE_NUMB) REFERENCES PRODUCTION_PLANTS(REACT_NAME,PROD_LANE_NUMB) ON DELETE CASCADE
);
The trigger i am trying to develop has the following purpose:
During the winter and summer months(December-February and June-August) the production plants cannot work at full load due to many weather related factors, such corrosion, pipe dilation/constriction and higher/lower temepratures. During these months the QUANTITY of raw materials sent daily to the plants, must be less than the average of total QUANTITY sent in the months preeciding those periods( November and May).
Now here's how i developed my trigger(Note: there is already another AFTER INSERT OR UPDATE trigger active on the table):
CREATE OR REPLACE TRIGGER METEO
AFTER INSERT OR UPDATE ON FEED
FOR EACH ROW
DECLARE
ACTL_MONTH CHAR(3); --ACTUAL MONTH WITHIN 3 LETTER FORMAT --
MONTH_AVG NUMBER(8) := 0; --PREECIDING MONTHS AVARAGE--
FEED_QUAN NUMBER(8) := 0; --ACTUAL FEED INSERTED/UPDATED--
BEGIN
--GETTING DATE FROM DUAL IN 3 LETTER FORMAT--
SELECT TO_CHAR(TRUNC(SYSDATE,'MONTH'),'MON') INTO ACTL_MONTH FROM DUAL;
--CHECKING DATE--
IF ACTL_MONTH='MAY' THEN
SELECT AVG(QUANTITY) INTO MONTH_AVG FROM FEED WHERE TO_CHAR(TRUNC(DATE_FEED,'MONTH'),'MON')='MAY';
END IF;
IF ACTL_MONTH='NOV' THEN
SELECT AVG(QUANTITY) INTO MONTH_AVG FROM FEED WHERE TO_CHAR(TRUNC(DATE_FEED,'MONTH'),'MON')='NOV';
END IF;
--SELECTING THE QUANTITY FEEDED--
SELECT :NEW.QUANTITY INTO FEED_QUAN FROM FEED;
IF MONTH_AVG<FEED_QUAN THEN
RAISE_APPLICATION_ERROR(-20008,'EXCEEDING FEED QUANTITY DUE TO WEATHER LIMITATIONS.ROLLBACK');
END IF;
END;
/
But every time i insert a value the trigger does not fire, and allows me to insert/update rows with not allowed values.
So:
Did i made mistakes in PL/SQL code?(It compiled with no errors)
May trigger cannot be fired upon dates?
Should i use another type of trigger structure?(statement?before?)
This is my first question on stack overflow so have mercy on me, and yes i have used google and used stack search for similar question but did not find anything like my problem, if something is not clear point it to me and i will adjust/explain; besisde consdier that im a foreign student so expect LOTS of english grammar errors.
There are a couple of different ways to solve this problem. First, create a second table to hold your monthly averages:
CREATE TABLE MONTHLY_AVERAGE_FEED
(MONTH_YEAR DATE -- 01-MM-YYYY
PRIMARY KEY,
TOTAL_QUANTITY NUMBER,
TRANSACTIONS NUMBER,
AVERAGE_QUANTITY NUMBER
GENERATED ALWAYS AS (CASE
WHEN TRANSACTIONS > 0 THEN
TOTAL_QUANTITY / TRANSACTIONS
ELSE 0
END));
and maintained by a trigger:
CREATE TRIGGER FEED_AVERAGE_AIUD
AFTER INSERT OR UPDATE OR DELETE ON FEED
FOR EACH ROW
BEGIN
IF UPDATING OR DELETING THEN
-- Back out the 'old' values
UPDATE MONTHLY_AVERAGE_FEED
SET TOTAL_QUANTITY = GREATEST(TOTAL_QUANTITY - :OLD.QUANTITY, 0),
TRANSACTIONS = GREATEST(TRANSACTIONS - 1, 0)
WHERE MONTH_YEAR = TRUNC(:OLD.DATE_FEED, 'MONTH');
END IF;
IF INSERTING OR UPDATING THEN
MERGE INTO MONTHLY_AVERAGE_FEED maf
USING (SELECT TRUNC(:NEW.DATE_FEED, 'MONTH') AS MONTH_YEAR
FROM DUAL) d
ON (maf.MONTH_YEAR = d.MONTH_YEAR)
WHEN MATCHED THEN
UPDATE
SET TOTAL_QUANTITY := TOTAL_QUANTITY +
(:NEW.QUANTITY *
CASE
WHEN INSERTING OR UPDATING THEN 1
ELSE -1
END),
TRANSACTIONS = TRANSACTIONS + 1
WHEN NOT MATCHED THEN
INSERT (MONTH_YEAR, TRANSACTIONS, TOTAL_QUANTITY)
VALUES (TRUNC(:NEW.DATE_FEED, 'MONTH'), 1, :NEW.QUANTITY);
END IF;
END FEED_AVERAGE_AIUD;
Then in your trigger you can simply query the MONTHLY_AVERAGE_FEED table to get the average feed for whatever month you want.
The second option would be to rewrite #MT0's trigger as a compound trigger. The "BEFORE STATEMENT" section of the trigger would handle computing the average feed for whatever month(s) you want, while the "BEFORE EACH ROW" section would contain the rest of the work.
Thanks to the answers and the help given by Bob Jarvis and MT0 i have finally solved my problem.
So i added a support table for the averages like Bob Jarvis suggested, and then added a specific trigger to populate it when any row is inserted into FEED table of my first post; here's the trigger modified which compile properly:
CREATE OR REPLACE TRIGGER FEED_AVERAGE_AIUD
AFTER INSERT OR UPDATE OR DELETE ON FEED
FOR EACH ROW
BEGIN
IF UPDATING OR DELETING THEN
-- Back out the 'old' values
UPDATE MONTHLY_AVERAGE_FEED
SET TOTAL_QUANTITY = GREATEST(TOTAL_QUANTITY - :OLD.QUANTITY, 0),
TRANSACTIONS = GREATEST(TRANSACTIONS - 1, 0)
WHERE MONTH_YEAR = TRUNC(:OLD.DATE_FEED, 'MONTH');
END IF;
IF INSERTING OR UPDATING THEN
MERGE INTO MONTHLY_AVERAGE_FEED maf
USING (SELECT TRUNC(:NEW.DATE_FEED, 'MONTH') AS MONTH_YEAR
FROM DUAL) d
ON (maf.MONTH_YEAR = d.MONTH_YEAR)
WHEN MATCHED THEN
UPDATE
SET TOTAL_QUANTITY = TOTAL_QUANTITY +:NEW.QUANTITY,
TRANSACTIONS = TRANSACTIONS + 1
WHEN NOT MATCHED THEN
INSERT (MONTH_YEAR, TRANSACTIONS, TOTAL_QUANTITY)
VALUES (TRUNC(:NEW.DATE_FEED, 'MONTH'), 1, :NEW.QUANTITY);
END IF;
END FEED_AVERAGE_AIUD;
/
So with the average table in place and running i created the following trigger to check the consitency beetwen the new inserted/updated values and the averages in specified months:
CREATE OR REPLACE TRIGGER METEO
AFTER INSERT OR UPDATE ON FEED
FOR EACH ROW
DECLARE
ACT_QUANT NUMBER; --ACTUAL INSERTED/UPDATED QUANTITY---
ACT_MONTH NUMBER; --MONTH AT WHICH THE QUANTITY WAS INSERTED/UPDATED--
REF_AVERG NUMBER; --THE AVERAGE IN THE AVERAGES TABLE REFEERING TO THE ISNERTED/UPDATED MONTH--
BEGIN
ACT_MONTH:= EXTRACT(MONTH FROM :NEW.DATE_FEED);
ACT_QUANT:= :NEW.QUANTITY;
-- SO IF I AM INSERTING/UPDATING VALUES IN JUNE/JULY/AUGUST
-- I SIMPLY SEARCH THE AVERAGE TABLE WITH A QUERY WITH MONTH AND YEAR TAKEN
-- BY THE DATE_FEED
IF ACT_MONTH IN(6,7,8) THEN
SELECT AVERAGE_QUANTITY
INTO REF_AVERG
FROM MONTHLY_AVERAGE_FEED
WHERE EXTRACT(MONTH FROM MONTH_YEAR)=5 AND
EXTRACT(YEAR FROM MONTH_YEAR)=EXTRACT(YEAR FROM :NEW.DATE_FEED);
ELSIF ACT_MONTH=12 THEN --FOR DECEMBER I TAKE THE SAME YEAR NOVEMBER AVG--
SELECT AVERAGE_QUANTITY
INTO REF_AVERG
FROM MONTHLY_AVERAGE_FEED
WHERE EXTRACT(MONTH FROM MONTH_YEAR)=11 AND
EXTRACT(YEAR FROM MONTH_YEAR)=EXTRACT(YEAR FROM :NEW.DATE_FEED);
ELSIF ACT_MONTH IN (1,2) THEN --FOR JANUARY AND FEBRUARY I TAKE THE AVG OF THE PREVIOUS YEAR --
SELECT AVERAGE_QUANTITY
INTO REF_AVERG
FROM MONTHLY_AVERAGE_FEED
WHERE EXTRACT(MONTH FROM MONTH_YEAR)=11 AND
EXTRACT(YEAR FROM MONTH_YEAR)=EXTRACT(YEAR FROM :NEW.DATE_ALIM)-1;
END IF;
IF ACT_QUANT>REF_AVERG THEN
RAISE_APPLICATION_ERROR(
-20008,
'EXCEEDING FEED QUANTITY DUE TO WEATHER LIMITATIONS.ROLLBACK'
);
END IF;
END;
/
The trigger compiled and worked as it was intended, it's not elegant for sure, but it does his job. As ever I had to translate every table/attributes names from my original language to english so it's possibile that i forgot something or mispelled word,verbs etc.
Anyway thanks to everyone who replied and helped,hoping this will help somebody else someday, thank you guys.
Change the trigger from AFTER to BEFORE.
You don't need to use SELECT ... INTO to assign variables.
You aren't answering the question. You need to check if the month is Dec-Feb or Jun-Aug and then find the daily average for Nov or May (respectively).
Rather than getting the average for all Mays (or Novembers), you need to get the average for only the preceding May (or November).
Like this:
SET DEFINE OFF;
CREATE OR REPLACE TRIGGER METEO
BEFORE INSERT OR UPDATE ON FEED
FOR EACH ROW
DECLARE
MONTH_START DATE;
MONTH_AVG NUMBER(8);
BEGIN
MONTH_START := CASE EXTRACT( MONTH FROM :NEW.DATE_FEED )
WHEN 12 THEN ADD_MONTHS( TRUNC( :NEW.DATE_FEED, 'MM' ), -1 )
WHEN 1 THEN ADD_MONTHS( TRUNC( :NEW.DATE_FEED, 'MM' ), -2 )
WHEN 2 THEN ADD_MONTHS( TRUNC( :NEW.DATE_FEED, 'MM' ), -3 )
WHEN 6 THEN ADD_MONTHS( TRUNC( :NEW.DATE_FEED, 'MM' ), -1 )
WHEN 7 THEN ADD_MONTHS( TRUNC( :NEW.DATE_FEED, 'MM' ), -2 )
WHEN 8 THEN ADD_MONTHS( TRUNC( :NEW.DATE_FEED, 'MM' ), -3 )
ELSE NULL
END;
IF MONTH_START IS NULL THEN
RETURN;
END IF;
SELECT AVG( QUANTITY )
INTO MONTH_AVG
FROM FEED
WHERE DATE_FEED >= MONTH_START
AND DATE_FEED < ADD_MONTHS( MONTH_START, 1 );
IF MONTH_AVG <= :NEW.QUANTITY THEN
RAISE_APPLICATION_ERROR(-20008,'EXCEEDING FEED QUANTITY DUE TO WEATHER LIMITATIONS.ROLLBACK');
END IF;
END;
/

automatic update of date when inserting new row

I'm trying to create a trigger that will update a column date by one month whenever a new row is added.
This is what I have, can someone tell me what I'm doing wrong?
CREATE OR REPLACE TRIGGER tg_nextupdate
BEFORE INSERT
ON Vehicle
FOR EACH ROW
BEGIN
IF :NEW.NextUpdate = SYSDATE
THEN
SET NextUpdate = ADD_MONTHS(SYSDATE,1);
END IF;
END;
There is no need of IF-END IF block, whenever a new row is inserted, it will have sysdate. So, just update the NextUpdate to ADD_MONTHS(SYSDATE,1) directly. The check on IF :NEW.NextUpdate = SYSDATE is not required.
CREATE OR REPLACE TRIGGER tg_nextupdate
BEFORE INSERT
ON Vehicle
FOR EACH ROW
BEGIN
:NEW.NextUpdate = ADD_MONTHS(SYSDATE,1);
END;
You can encounter a problem with your code when NextUpdate contains only date, without of hours, minutes and seconds.
Try this:
CREATE OR REPLACE TRIGGER tg_nextupdate
BEFORE INSERT
ON Vehicle
FOR EACH ROW
BEGIN
IF :NEW.NextUpdate = trunc(SYSDATE)
THEN
SET NextUpdate = ADD_MONTHS(SYSDATE,1);
END IF;
END;
Or give us more details about what you want and what you get with your code.
This is what I have, can someone tell me what I'm doing wrong?
Assuming NextUpdate having for default value SYSDATE, as it has already been say, you IF is maybe "not necessary"...
... but, as of myself, I think the real issue is SYSDATE not guaranteeing to return the same value upon each call. If you don't believe me, try that http://sqlfiddle.com/#!4/1f810/2
So, your column might very well be properly initialized by SYSDATE to, say "October, 26 2014 18:50:10+0000". But, in your trigger, SYSDATE might very well return "October, 26 2014 18:50:11+0000". This would be bad luck, I admit. And maybe this is acceptable in your application. But in a more general case, this might easily become a hard to track bug.
Depending your needs, I would suggest one of those three options instead:
1) Assuming SYSDATE is a "magical value" meaning "hey trigger! Compute the right value for NextUpdate":
CREATE OR REPLACE TRIGGER tg_nextupdate
BEFORE INSERT
ON Vehicle
FOR EACH ROW
BEGIN
IF :NEW.NextUpdate <= SYSDATE
THEN
:NEW.NextUpdate := SYSDATE + INTERVAL '1' MONTH;
END IF;
END;
So, any time in the past will trigger the calculation of a new NextUpdate. Including 1s in the past.
2) Override NextUpdate from the trigger -- always:
CREATE TABLE Vehicle (value NUMBER(10),
NextUpdate DATE)
-- ^^^^^^^^^^^^^^^
-- No need for default here
-- as we override values
/
CREATE OR REPLACE TRIGGER tg_nextupdate
BEFORE INSERT
ON Vehicle
FOR EACH ROW
BEGIN
:NEW.NextUpdate := SYSDATE + INTERVAL '1' MONTH;
END;
/
INSERT INTO Vehicle(value) VALUES (1)
/
INSERT INTO Vehicle VALUES (2, TO_DATE('30/10/2014','DD/MM/YYYY'))
/
INSERT INTO Vehicle VALUES (3, TO_DATE('30/12/2014','DD/MM/YYYY'))
/
INSERT INTO Vehicle VALUES (4, NULL)
/
3) Set NextUpdate defaults to SYSDATE + INTERVAL '1' MONTH, allow the user to change that when inserting. If you need it, a trigger might keep the LEAST value (+/- the 1 second error as explained in preamble):
CREATE TABLE Vehicle (value NUMBER(10),
NextUpdate DATE DEFAULT SYSDATE + INTERVAL '1' MONTH)
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- set default to the "most probable" value
/
CREATE OR REPLACE TRIGGER tg_nextupdate
BEFORE INSERT
ON Vehicle
FOR EACH ROW
DECLARE
LimitNextUpdate DATE := SYSDATE + INTERVAL '1' MONTH;
BEGIN
:NEW.NextUpdate := LEAST(LimitNextUpdate,
NVL(:NEW.NextUpdate,LimitNextUpdate));
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- required if the used set the value to NULL
END;
/
INSERT INTO Vehicle(value) VALUES (1)
/
INSERT INTO Vehicle VALUES (2, TO_DATE('30/10/2014','DD/MM/YYYY'))
/
INSERT INTO Vehicle VALUES (3, TO_DATE('30/12/2014','DD/MM/YYYY'))
/
INSERT INTO Vehicle VALUES (4, NULL)
/
You will need to add extra logic (either in the trigger or as a check constraint) in order to reject NextUpdate in the past.

Query to find whether a table was updated within a specific time period

Table1
Emp_no|| end_date || col2 || Sent date
This table will send the details of a particular employee and the sent date column will be updated as sysdate whenever the detail is entered in this table.
Now for the second run ill have to check that was the mail sent for the same employee within 15 days ? if yes then the row will not be updated in the table1. i.e. i have to compare the latest sent date and sysdate. For this i am using a function
create or replace Function last_mail_sent(p_emp_no number,pay_period_end_date date)
return number
is
begin
select trunc(sysdate)-trunc(sent_date)
into
l_days
from table1
where emp_no=p_emp_no
and sent_date=(select max(sent_date) from tabl1
where emp_no=p_emp_no
and trunc(end_date)=trunc(pay_period_end_date );
exception when no_data_found
then
l_days :=0;
else
when others then
l_days:=-1;
end;
return l_days;
end;
/
The logic i was trying to use in the package where i have used this funcn to decide whether or not to insert was :
l_last_mail_sent := last_mail_sent(pass the parameter by fetching cols from cursor)
if l_last_mail_sent=0 (That is no row is fetched from the function)
or l_last_mail_sent>15
then
insert into Table1
else
--do not insert
end if;
But the problem with the above query is . that for example if the table was updated today the sent_date column was updated with todays date then also the function will return 0. Is there a better logic that can be formed ? P.S :-I have to create a function to deal with this as this will be reusable.
select trunc(sysdate) - trunc(max(sent_date))
into l_days
from table1
where emp_no = p_emp_no
and end_date between trunc(pay_period_end_date) and trunc(pay_period_end_date) + 1 - 1/24/60/60;
(This query won't raise any exceptions so you don't need to catch anything)
I've changed the condition a bit so you can use an index on an end_date (if any)
And then
if l_last_mail_sent is null or l_last_mail_sent > 15 then
--insert into Table1
else
--do not insert
end if;