简体   繁体   English

PL / SQL过程语法

[英]PL/SQL Procedure Syntax

So i'm having a little trouble with some PL SQL statements. 因此,我在使用某些PL SQL语句时遇到了一些麻烦。 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! 我只是PL的新手!

You can't CREATE a VIEW inside a procedure using DDL (you would have to use EXECUTE IMMEDIATE to do so). 您不能在使用DDL的过程中创建VIEW(您必须使用EXECUTE IMMEDIATE这样做)。

I would prefer to set the WHERE-Clause of the SELECT statement directly: 我希望直接设置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;

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. 在过程中编写ddl并不是一种好的样式。 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 如果要这样做,请将Create View放入动态SQL语句中,如下面的代码段所示
  3. All the DB Objects on which you want to access from the procedure, have to exist at compile time. 您要从过程中访问的所有DB对象都必须在编译时存在。 So this code will never work unless you write all your Select statements also in dynamic SQL. 因此,除非您也使用动态SQL编写所有Select语句,否则此代码将永远无法工作。
  4. Don't name your parameters "start" or "end". 不要将参数命名为“开始”或“结束”。 Theese are reserved words and is therefor not allowed. Theese是保留字,因此是不允许的。
  5. If you call the dateOrder procedure make sure that you will pass a valid date as parameters. 如果调用dateOrder过程,请确保将有效日期作为参数传递。 In your example you will pass strings. 在您的示例中,您将传递字符串。 Maybe this will work with your default NLS but in another environment/database it may not. 也许这将与您的默认NLS一起使用,但在其他环境/数据库中可能无法使用。

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. 您只想检查HasContract值等于name参数的行。 Fine, write the query just as you want it then add HasContract = name to the where clause. 好的,根据需要编写查询,然后将HasContract = name添加到where子句。 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 . 或者,以等式形式e1 <= s2 or s1 >= e2 A little Boolean magic and we can invert to e1 > s2 and s1 < e2 . 一点点布尔魔术,我们可以求出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. 简单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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