CURRENT_DATE Oracle - oracle

I'm having hard time to add a new colomn of date of birth with the check rule age between 18 and 65.
I'm using sqplus with Oracle
Alway getting the error message ORA00920
Need your help please
ALTER TABLE Vendeur ADD (dateNaissance DATE,
dateDebutProjet DATE NOT NULL,
DateFinProjet DATE NOT NULL,
CONSTRAINT chk_date_Birth CHECK ((TRUNC(CURRENT_DATE)-dateNaissance)
BETWEEN 18 AND 65),
CONSTRAINT chk_date_Projet CHECK (DateFinProjet > dateDebutProjet));

if it can help, the solution without triggers (since we didn't learn hem at that time):
ALTER TABLE Vendeur ADD (dateNaissance DATE,
debutProjet DATE DEFAULT '01/01/1000' NOT NULL,
finProjet DATE DEFAULT '02/01/1000' NOT NULL,
dateDuJour Date DEFAULT CURRENT_DATE,
CONSTRAINT chk_date_Projet CHECK (finProjet > debutProjet),
CONSTRAINT chk_date_Birth CHECK ((dateDuJour - dateNaissance)\365 BETWEEN 18 AND 65)
);

Check constraints cannot call non-deterministic functions like CURRENT_DATE. Check constraints are supposed to always be true, weird things might happen if check constraints aged out.
The below sample code shows one of the errors you might get trying to use CURRENT_DATE in a check constraint:
SQL> create table test1(a date);
Table created.
SQL> alter table test1 add constraint test1_ck1 check(a > date '2000-01-01');
Table altered.
SQL> alter table test1 add constraint test1_ck2 check(a > current_date);
alter table test1 add constraint test1_ck2 check(a > current_date)
*
ERROR at line 1:
ORA-02436: date or system variable wrongly specified in CHECK constraint
Create a trigger to workaround this problem:
create or replace trigger test1_date_gt_today
before update or insert of a on test1
for each row
begin
if :new.a is null or :new.a < current_date then
raise_application_error(-20000, 'The date cannot be earlier than today.');
end if;
end;
/
Below is an example of one INSERT working, and one failing to meet the condition in the trigger:
SQL> insert into test1 values(sysdate + 1);
1 row created.
SQL> insert into test1 values(sysdate - 1);
insert into test1 values(sysdate - 1)
*
ERROR at line 1:
ORA-20000: The date cannot be earlier than today.
ORA-06512: at "JHELLER.TEST1_DATE_GT_TODAY", line 3
ORA-04088: error during execution of trigger 'JHELLER.TEST1_DATE_GT_TODAY'

Related

How to make constraint on Dates

I come the to problem with creating database table over JPA. I have some atributes for creating database table together with two fields for Date. I need to make sure, that input for DateEnd must be bigger than input for DateStart
#Column(name="START")
private LocalDate dateStart
#Column(name="END")
private LocalDate dateEnd
Thanks for any advice
It's not possible on entity level, you should define your custom costraint with its javax.validation.ConstraintValidator implementation. See here for documentation.
As you tagged it as an "Oracle" question, and if you want to do that in the database, a natural choice would be the CHECK constraint.
Here's an example (note that the date literal's format is 'YYYY-MM-DD'):
SQL> create table test (id number, date_start date, date_end date);
Table created.
SQL> alter table test add constraint ch_test_date check (date_start <= date_end);
Table altered.
SQL> insert into test values (1, date '2018-03-19', date '2018-05-10');
1 row created.
SQL> update test set date_end = date '2010-01-02' where id = 1;
update test set date_end = date '2010-01-02' where id = 1
*
ERROR at line 1:
ORA-02290: check constraint (SCOTT.CH_TEST_DATE) violated
SQL> insert into test values (1, date '2018-03-19', date '2018-01-02');
insert into test values (1, date '2018-03-19', date '2018-01-02')
*
ERROR at line 1:
ORA-02290: check constraint (SCOTT.CH_TEST_DATE) violated
SQL>

Why oracle sql not allow sysdate in table creation time for count age?

Query....
I want to try to make check constraints on birthdate and check age should be greater than 18.
Create table emp
(
Birthdate date,
Check( MONTHS_BETWEEN(SYSDATE,Birthdate))
);
Error on above query....why?
Anyone help me...
Why oracle sql not allow sysdate in table creation time for count age?
SYSDATE is not allowed because the constraint must be either "true" or "false" at any time you look at the data. If you were able to use SYSDATE in a check constraint, you could insert a row that satisfied the constraint at that time, but the constraint would be violated later. No good!
In your example, once the constraint is satisfied at insert time, it can't become "not satisfied" later. But here you are asking Oracle to think. It can't. It just doesn't allow you to use SYSDATE in constraints. Period.
Instead, you should write a simple trigger to do the check for you. Note that you are missing the comparison to 18 * 12 in your purported check constraint; MONTHS_BETWEEN may give some weird results in some cases; and it is always best to write code that mirrors your thinking: in this case the condition (in a trigger, not a check constraint) should be ***
sysdate >= birthdate + interval '18' year
*** EDIT: As Alex Poole points out below, adding INTERVAL to a date may sometimes be as weird as MONTHS_BETWEEN. The safe way to write the check is
sysdate >= add_months ( birthdate, 18 * 12 ) -- age >= 18 years or 18 * 12 months
(That is how I would write it - with the comment to explain the purpose, and 18 * 12.)
Maybe try:
SQL> create table person
(name varchar2(100),
dob date,
created_date date default sysdate not null,
constraint dob_check check
(
dob <= add_months(trunc(created_date), (12*18)*-1)
)
)
Table created.
SQL> insert into person(name,dob) values ('Bob', to_date('19740101','YYYYMMDD'))
1 row created.
SQL> commit
Commit complete.
SQL> insert into person(name,dob) values ('Jane', to_date('20050101','YYYYMMDD'))
insert into person(name,dob) values ('Jane', to_date('20050101','YYYYMMDD'))
Error at line 17
ORA-02290: check constraint (MYUSER.DOB_CHECK) violated
This is because of Oracle limitation. The reason is SYSDATE is non-deterministic. You can get a different result every time you call it. So the outcome (true/false) can (will) change over time. So Oracle can't guarantee that the expression is always true for every row.
See also https://asktom.oracle.com/pls/apex/asktom.search?tag=sysdate-in-check-constraints

Trigger to update week of the year

I want to write a trigger so that when decom_date is inserted or updated the week of the year is updated to the corresponding value.
This is what I have so far, but after inserting a date the week is still null.
create or replace trigger test_trigger
before insert on check_decom
for each row
begin
if inserting then
update check_decom set decom_week= (select to_char(to_date(decom_date,'DD-
MON-YY'),'WW') as week from check_decom) ;
end if;
end;
/
SQL> select * from check_decom;
DECOM_DATE DECOM_WEEK
------------------------------ ----------
23-JUN-17
What am I doing wrong?
Example for Week of a year
SQL> select to_char(to_date(sysdate,'DD-MON-YY'),'WW') as week from dual;
WE
--
28
You're doing a couple of things wrong, starting with date handling. Your decom_date column should be defined as a DATE column - it looks like it might be a string in your sample output. But your handling with sysdate is also wrong, as you're implicitly converting to a string in order to convert it back to a date, which is both pointless and prone to error as this might happen in a session which has different NLS settings. If your column is actually a DATE then you should not be calling to_date() against that either; and if it is a string then that conversion is valid but it should be a DATE.
Then your trigger is querying and trying to update the table that the trigger is against. With no data that doesn't error but doesn't do anything as there is no existing row to update - the one you are inserting doesn't exist yet. If there was data you would get a mutating table error, if you didn't get a too-many-rows exception from the select part.
Row-level triggers can access NEW and OLD pseudorecords to see and manipulate the affected row; you don't need to (and generally can't) use DML queries to access the data in the row you're manipulating.
If your table was defined with a date column and a number column:
create table check_decom(decom_date date, decom_week number);
then your trigger might look something like:
create or replace trigger test_trigger
before insert on check_decom
for each row
begin
if inserting then
:new.decom_week := to_number(to_char(:new.decom_date, 'WW'));
end if;
end;
/
although the if inserting check is a bit pointless as the trigger will only fire on insert anyway. Which in itself might be an issue; you perhaps want it to be set on update as well, but the logic the same, so would be:
create or replace trigger test_trigger
before insert or update on check_decom
for each row
begin
:new.decom_week := to_number(to_char(:new.decom_date, 'WW'));
end;
/
which does what you want:
insert into check_decom (decom_date) values (date '2017-06-23');
1 row inserted.
select * from check_decom;
DECOM_DAT DECOM_WEEK
--------- ----------
23-JUN-17 25
But I wouldn't do this with a trigger at all. From Oracle 11g you can use a virtual column instead:
create table check_decom (
decom_date date,
decom_week generated always as (to_number(to_char(decom_date, 'WW')))
);
Table CHECK_DECOM created.
insert into check_decom (decom_date) values (date '2017-06-23');
1 row inserted.
select * from check_decom;
DECOM_DAT DECOM_WEEK
--------- ----------
23-JUN-17 25

SQL Error: ORA-04091: table is mutating while updating by a trigger

i am new to oracle , i am developing a hospital management system , i have this table to store patients :
create table patients(
p_id number not null primary key,
p_fullname full_name_ty,
p_gender char,
de_no number,
p_entry date ,
Diagnosis varchar2(25),
p_exit date,
constraint pdf foreign key (de_no) references department(dep_no)
);
where p_entry is the date when a patient enters the hospital , i made a trigger that calculates the residency time in the hospital on after the upadate of the (p_exit) date for the patient (setting this date means that the patient has left the hospital) , the trigger will simply calculate the difference between the two dates , and print it , here is the code of the trigger :
create or replace
trigger period_trig before update of p_exit on patients for each row
DECLARE
period Number(3);
enterr DATE;
exitt DATE;
BEGIN
enterr := :old.P_ENTRY;
exitt:= :NEW.P_EXIT;
Period :=exitt-enterr;
DBMS_OUTPUT.PUT_LINE('Duration:'||period);
update patients SET RESIDENCY= Period where P_ID = :old.P_ID;
end period_trig
put when i test the trigger and use an update statement like this :
update patients set p_exit = to_date('01/02/2001','dd/mm/yyyy') where p_id = 2;
and run it i get this error :
Error starting at line 1 in command:
update patients set p_exit = to_date('01/02/2001','dd/mm/yyyy') where p_id = 2
Error report:
SQL Error: ORA-04091: table SEM.PATIENTS is mutating, trigger/function may not see it
ORA-06512: at "SEM.UPDATEPAT", line 5
ORA-06512: at "SEM.PERIOD_TRIG", line 10
ORA-04088: error during execution of trigger 'SEM.PERIOD_TRIG'
04091. 00000 - "table %s.%s is mutating, trigger/function may not see it"
*Cause: A trigger (or a user defined plsql function that is referenced in
this statement) attempted to look at (or modify) a table that was
in the middle of being modified by the statement which fired it.
*Action: Rewrite the trigger (or function) so it does not read that table.
Error starting at line 1 in command:
update patients set p_exit = to_date('01/02/2001','dd/mm/yyyy') where p_id = 2
Error report:
SQL Error: ORA-04091: table SEM.PATIENTS is mutating, trigger/function may not see it
ORA-06512: at "SEM.PERIOD_TRIG", line 11
ORA-04088: error during execution of trigger 'SEM.PERIOD_TRIG'
04091. 00000 - "table %s.%s is mutating, trigger/function may not see it"
*Cause: A trigger (or a user defined plsql function that is referenced in
this statement) attempted to look at (or modify) a table that was
in the middle of being modified by the statement which fired it.
*Action: Rewrite the trigger (or function) so it does not read that table.
can anyone tell me how to fix it ? and thanks so much ..
You are modifying the very same table in the trigger that is currently being modified. As they error tells you:
*Cause: A trigger (or a user defined plsql function that is referenced in
this statement) attempted to look at (or modify) a table that was
in the middle of being modified by the statement which fired it.
*Action: Rewrite the trigger (or function) so it does not read that table.
There is actually no need in updating the table again, you can simply use a virtual column directly on the table that makes the entire trigger redundant:
CREATE TABLE patients(
p_id NUMBER NOT NULL PRIMARY KEY,
p_fullname VARCHAR2(255),
p_gender CHAR(1),
de_no NUMBER,
p_entry DATE,
Diagnosis VARCHAR2(25),
p_exit DATE,
RESIDENCY NUMBER GENERATED ALWAYS AS (p_exit-p_entry)
);
insert into patients (p_id, p_fullname, p_gender, de_no, p_entry, diagnosis) values (1, 'GVENZL', 'M', 1234, SYSDATE-1, 'healthy' );
commit;
select p_fullname, residency from patients;
update patients set p_exit = sysdate;
commit;
select p_fullname, residency from patients;

Trigger problems in PLSQL

I've been trying to get a trigger that will essentially run a constraint like this;
CONSTRAINT (Date <= Meeting.EndDate)
Where it will compare the Date stated in one table (Race) with the Date stated in another table (Meeting). I know I could achieve this using foreign keys but I'm pretty sure to get more marks I need to use a trigger.
So far I've got this:
CREATE OR REPLACE TRIGGER race_date_trg
AFTER INSERT OR UPDATE
ON RACE
FOR EACH ROW
DECLARE
MEETING_ENDDATE DATE;
STARTDATE race.racedate%TYPE;
BEGIN
SELECT ENDDATE INTO MEETING_ENDDATE FROM meeting;
IF STARTDATE > MEETING_ENDDATE THEN
RAISE_APPLICATION_ERROR(-20000, 'Wrong start date!');
END IF;
end race_date_trg;
It compiles fine, but when I try and populate my tables with something that will raise the error, I'm getting this:
Error report:
SQL Error: ORA-04091: table SE488.MEETING is mutating, trigger/function may not see it
ORA-06512: at "SE488.RACE_DATE_TRG", line 5
ORA-04088: error during execution of trigger 'SE488.RACE_DATE_TRG'
04091. 00000 - "table %s.%s is mutating, trigger/function may not see it"
*Cause: A trigger (or a user defined plsql function that is referenced in
this statement) attempted to look at (or modify) a table that was
in the middle of being modified by the statement which fired it.
*Action: Rewrite the trigger (or function) so it does not read that table.
Thanks for the help.
Creation of the tables:
CREATE TABLE Meeting
(
MeetLocation varchar2(60),
StartDate date,
EndDate date,
MeetName varchar2(60)
);
CREATE TABLE Race
(
RaceID NUMBER,
RaceLocation varchar2(60),
MeetingStart date,
RaceDate date,
RaceTime timestamp(0),
RaceName varchar2(60),
RaceType varchar2(8),
MinAge numeric(2),
MaxAge numeric(2),
Sex varchar2(2) NULL
);
Populating them:
INTO Meeting (MeetLocation,StartDate,EndDate,MeetName)
values('Talbot','30-Jul-05','07-Aug-05','Midlands Derby')
INTO Meeting (MeetLocation,StartDate,EndDate,MeetName)
values('Ascot','04-Jul-10','07-Aug-10','National Derby')
INTO Race (RaceID,RaceLocation,MeetingStart,RaceDate,RaceTime,RaceName,RaceType,MinAge,MaxAge,Sex)
values('1','Talbot','20-Jul-05','31-Jul-05',to_date('2005/07/31:12:00:00PM', 'yyyy/mm/dd:hh:mi:sspm'),'600m Dash','Flat','2','10','M')
INTO Race (RaceID,RaceLocation,MeetingStart,RaceDate,RaceTime,RaceName,RaceType,MinAge,MaxAge,Sex)
values('2','Talbot','30-Jul-05','01-Aug-05',to_date('2005/08/01:01:10:00PM', 'yyyy/mm/dd:hh:mi:sspm'),'1km Hurdles','Flat','6','12','F')
CREATE OR REPLACE TRIGGER race_date_trg
BEFORE INSERT OR UPDATE ON RACE
FOR EACH ROW
DECLARE
meet_date date;
start_date date := :new.RaceDate;
BEGIN
SELECT StartDate INTO meet_date FROM meeting WHERE MeetLocation = :new.RaceLocation;
IF start_date > meet_date THEN
RAISE_APPLICATION_ERROR(-20000, 'Wrong start date!');
END IF;
END race_date_trg;
/
I Think you want raise error or exception. When someone insert or update table race, If start date (from table race) is lower than meet date (from table meeting).
:D

Resources