简体   繁体   中英

PL/SQL Procedure Syntax

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!

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;

So a few things will not work in you procedure. Take this as recommendation not as a solution:

  1. It is not a good style to code a ddl within a procedure. And by the way to access the new view within this procedure is impossible!!
  2. If you want to do so, put the Create View in a dynamic SQL statement like the code snippet below
  3. All the DB Objects on which you want to access from the procedure, have to exist at compile time. So this code will never work unless you write all your Select statements also in dynamic SQL.
  4. Don't name your parameters "start" or "end". Theese are reserved words and is therefor not allowed.
  5. If you call the dateOrder procedure make sure that you will pass a valid date as parameters. In your example you will pass strings. Maybe this will work with your default NLS but in another environment/database it may not.

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;

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.

  • if the end date of one is less than or equal to the start date of the other or
  • if the start date of one is greater than or equal to the end data of the other.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM