Reputation: 73
So i'm having a little trouble with some PL SQL statements. Essentially i'm trying to create a procedure that will check that when a new tuple is inserted, the procedure checks that there isn't another contract for the same person within the same dates ie. the dates of the new contract don't overlap the dates of the other.
Here is the code:
CREATE OR REPLACE PROCEDURE dateOrder
(name IN VARCHAR2, start IN DATE, end IN DATE)
IS
x number;
y number;
BEGIN
CREATE OR REPLACE VIEW PersonContracts AS
SELECT * FROM ContractInfo WHERE HasContract=name;
SELECT COUNT(*) INTO x FROM PersonContracts
WHERE start BETWEEN date_from AND date_to;
SELECT COUNT(*) INTO y from PersonContracts
WHERE end BETWEEN date_from AND date_to;
IF x > 0 THEN
dbms_output.put_line("overlaps.");
END IF;
IF Y > 0 THEN
dbms_output.put_line("overlaps.");
END IF;
END dateOrder;
/
BEGIN
dateOrder("John Smith", "08-oct-2014", "12-oct-2014");
END;
I have tried it with or without the view but i would prefer to keep the view if possible. I'm only new at PL!
Upvotes: 0
Views: 1289
Reputation: 5636
The view is unnecessary even if it was allowed. You want to examine only rows that has HasContract
values that are equal to the name
parameter. Fine, write the query just as you want it then add HasContract = name
to the where
clause. Don't over-think simple solutions.
Also, you can find out what you need in one query. The condition you want to catch is if there is any overlap between the interval defined by the start and stop dates and any existing start and stop dates. While we could painstakingly list out every conceivable arrangement that would lead to an overlap, let's look at the only two arrangements that don't lead to an overlap.
Or, in equation form e1 <= s2 or s1 >= e2
. A little Boolean magic and we can invert to e1 > s2 and s1 < e2
. That gives us the simplified query:
select COUNT(*) into y
from ContractInfo
where HasContract = name
and p_end > date_from
and p_start < date_to;
If this query returns any non-zero answer, there will be an overlap somewhere. One simple query, one check afterwards. Easy.
Upvotes: 0
Reputation: 505
So a few things will not work in you procedure. Take this as recommendation not as a solution:
Check this out:
CREATE OR REPLACE PROCEDURE dateOrder
(name IN VARCHAR2, xstart IN DATE, xend IN DATE)
IS
x number;
y number;
BEGIN
execute immediate (
'CREATE OR REPLACE VIEW PersonContracts AS
SELECT * FROM ContractInfo ....'
);
-- that won't work, because the PersonContracts will be not there at compile time.
SELECT COUNT(*) INTO x FROM PersonContracts
WHERE start BETWEEN date_from AND date_to;
SELECT COUNT(*) INTO y from PersonContracts
WHERE end BETWEEN date_from AND date_to;
IF x > 0 THEN
dbms_output.put_line("overlaps.");
END IF;
IF Y > 0 THEN
dbms_output.put_line("overlaps.");
END IF;
END dateOrder;
BEGIN
dateOrder("John Smith", "08-oct-2014", "12-oct-2014");
END;
Upvotes: 1
Reputation: 2532
You can't CREATE a VIEW inside a procedure using DDL (you would have to use EXECUTE IMMEDIATE to do so).
I would prefer to set the WHERE-Clause of the SELECT statement directly:
CREATE OR REPLACE PROCEDURE dateOrder (name IN VARCHAR2, start IN DATE, end IN DATE)
IS
x number;
y number;
BEGIN
SELECT COUNT(*) INTO x FROM ContractInfo WHERE HasContract=name
AND start BETWEEN date_from AND date_to;
SELECT COUNT(*) INTO y from ContractInfo WHERE HasContract=name
AND end BETWEEN date_from AND date_to;
IF x > 0 THEN
dbms_output.put_line("overlaps.");
END IF;
IF Y > 0 THEN
dbms_output.put_line("overlaps.");
END IF;
END dateOrder;
/
BEGIN
dateOrder("John Smith", "08-oct-2014", "12-oct-2014");
END;
Upvotes: 1