PL / SQL过程语法

时间:2014-12-12 15:31:02

标签: sql oracle plsql procedure

所以我对一些PL SQL语句有点麻烦。基本上我正在尝试创建一个程序来检查当插入新元组时,程序检查在同一日期内没有同一个人的另一个合同,即。新合同的日期与另一合同的日期不重叠。

以下是代码:

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;

我在有或没有视图的情况下尝试了它,但我更愿意保留视图(如果可能)。我只是PL的新人!

3 个答案:

答案 0 :(得分:1)

您无法在使用DDL的过程中创建VIEW(您必须使用EXECUTE IMMEDIATE来执行此操作)。

我更喜欢直接设置SELECT语句的WHERE-Clause:

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;

答案 1 :(得分:1)

所以有些事情在你的程序中是行不通的。以此为推荐而非解决方案:

  1. 在过程中编写ddl不是一种好方法。顺便说一下,在这个过程中访问新视图是不可能的!!
  2. 如果您想这样做,请将Create View放在动态SQL语句中,如下面的代码片段
  3. 要从过程中访问的所有数据库对象必须在编译时存在。因此,除非您在动态SQL中编写所有Select语句,否则此代码将永远不会工作。
  4. 不要命名您的参数"开始"或者"结束"。 Theese是保留字,因此不允许。
  5. 如果您调用dateOrder程序,请确保将有效日期作为参数传递。在您的示例中,您将传递字符串。也许这适用于您的默认NLS,但在其他环境/数据库中可能不会。
  6. 检查出来:

    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;
    

答案 2 :(得分:0)

即使允许,视图也是不必要的。您只想检查HasContract值等于name参数的行。好的,按照您的意愿编写查询,然后将HasContract = name添加到where子句中。不要过度思考简单的解决方案。

此外,您可以在一个查询中找到所需内容。您要捕获的条件是,开始和停止日期定义的间隔与任何现有的开始和停止日期之间是否存在任何重叠。虽然我们可以煞费苦心地列出可能导致重叠的所有可能的安排,但让我们看看导致重叠的两种安排。

  • 如果一个的结束日期小于或等于另一个的开始日期或
  • 如果一个的开始日期大于或等于另一个的结束数据。

或者,在等式中e1 <= s2 or s1 >= e2。一点布尔魔术,我们可以反转为e1 > s2 and s1 < e2。这为我们提供了简化的查询:

select COUNT(*) into y
from   ContractInfo
where  HasContract = name
  and  p_end   > date_from
  and  p_start < date_to;

如果此查询返回任何非零答案,则会在某处出现重叠。一个简单的查询,一个检查后。容易。