PL/SQL 代码不向表中插入记录

Posted

技术标签:

【中文标题】PL/SQL 代码不向表中插入记录【英文标题】:PL/SQL code not inserting records into table 【发布时间】:2015-10-24 05:18:39 【问题描述】:

背景:我正在使用 oracle SQLDeveloper,我有表格:

TUTPRAC:CLASSID (PK)、UNITCODE、STAFFNO、CLASSDAY、CLASSTIME、CLASSTYPE、ROOMNUM

UNITSTREAM:STREAMID (PK)、UNITCODE、STAFFNO、日期、时间、位置

问题:无论我尝试使用该程序输入什么,我当前的代码都不会输入记录,即使该记录在日期、时间和房间方面是完全唯一的。

我正在尝试使用该程序执行的操作是检查是否有任何课程已经占用了我尝试使用该程序输入的记录的日期/时间/房间。

要成功添加记录=单元(例如COMP111(UNITCODE))不能在同一天(无论时间或地点)有任何课程。它也不能与另一个单元分配同一个房间,以防止两个班级被预订到同一个教室(例如 SCIE112)。最后,该单元不能有与该单元讲座相同的课程(讲座详细信息存储在 UNITSTREAM 表中)。

TUTPRACS 包含教程和实践的记录,而 UNITSTREAM 包含流(讲座)的记录。

我对 PL/SQL 还很陌生,因此我们将不胜感激。到目前为止我的代码:

CREATE OR REPLACE PROCEDURE OPEN_CLASS(
           p_class IN TUTPRAC.CLASSID%TYPE,
           p_unitc IN TUTPRAC.UNITCODE%TYPE,
           p_classd IN TUTPRAC.CLASS_DAY%TYPE,
           p_classt IN TUTPRAC.CLASS_TIME%TYPE,
           p_classtp IN TUTPRAC.CLASS_TYPE%TYPE,
           p_roomnm IN TUTPRAC.ROOMNUM%TYPE)
    IS
   x NUMBER:=0;
   y NUMBER:=0;  
BEGIN

    -- checks
    SELECT nvl((SELECT 1 FROM TUTPRAC WHERE CLASS_DAY = p_classd and CLASS_TIME = p_classt and CLASS_TYPE = p_classtp and ROOMNUM = p_roomnm) , 0) INTO x FROM dual;
    SELECT nvl((SELECT 1 FROM UNITSTREAM WHERE UNITCODE = p_unitc and DAY = p_classd and TIME = p_classt and LOCATION = p_roomnm) , 0) INTO y FROM dual;

    -- insert
    IF (x = 1 and y = 1) THEN
        INSERT INTO TUTPRAC ("CLASSID", "UNITCODE", "CLASS_DAY", "CLASS_TIME", "CLASS_TYPE", "ROOMNUM") 
      VALUES (p_class, p_unitc, p_classd, p_classt, p_classtp, p_roomnm);
    END IF;
END OPEN_CLASS;

【问题讨论】:

有点像是在碰撞确实存在时创建类,而不是在它们不存在时。您不希望 x 和 y 为零吗? 您是否在调用过程后提交更改?默认的 oracle 安装没有像 SQL Server 那样的自动提交。 我刚刚将 if 语句的 X 和 Y 值更改为 0。现在的问题是它检测到冲突的唯一时间是所有字段是否匹配。但是,例如,如果我打开一个具有相同单位代码/日期/时间但不同房间的课程,它将创建记录。我想要的是确保该单元在那天没有任何其他课程(tut/pracs)或讲座。 @Paul Kientitz 我认为在测试中使用 ors 而不是 ands。 我收到错误:BEGIN OPEN_CLASS('TUTE_6', 'COMP355', 'Wed', '12:00', 'T', 'E5A180');结尾;错误报告 - ORA-01427:单行子查询返回多于一行 ORA-06512:在“OPEN_CLASS”第 14 行 ORA-06512:在第 2 行 01427。00000 -“单行子查询返回多于一行”*原因:*行动:@Paul Kienitz 【参考方案1】:

初学者可以试试这个。您可能希望以不同的方式处理异常和/或向调用此过程的程序返回一些内容以使其知道“成功”或“失败”。但如果您愿意,我们可以稍后再做。

    CREATE OR REPLACE PROCEDURE OPEN_CLASS(
               p_class IN TUTPRAC.CLASSID%TYPE,
               p_unitc IN TUTPRAC.UNITCODE%TYPE,
               p_classd IN TUTPRAC.CLASS_DAY%TYPE,
               p_classt IN TUTPRAC.CLASS_TIME%TYPE,
               p_classtp IN TUTPRAC.CLASS_TYPE%TYPE,
               p_roomnm IN TUTPRAC.ROOMNUM%TYPE)
        IS
       x NUMBER := 0;
       y NUMBER := 0;  
       exc_*** EXCEPTION;
       PRAGMA EXCEPTION_INIT(exc_***, -22000);

    BEGIN

        -- checks for conflicts
        SELECT 1 
        INTO x
        FROM TUTPRAC 
        WHERE CLASS_DAY = p_classd 
        and CLASS_TIME = p_classt 
        and CLASS_TYPE = p_classtp 
        and ROOMNUM = p_roomnm;

        SELECT 1 
        INTO y
        FROM UNITSTREAM 
        WHERE UNITCODE = p_unitc 
        and DAY = p_classd 
        and TIME = p_classt 
        and LOCATION = p_roomnm;

        -- exception if conflict else insert class.
        IF (x = 1 OR y = 1) THEN
          RAISE exc_***;
        ELSE
          INSERT INTO TUTPRAC ("CLASSID", "UNITCODE", "CLASS_DAY", "CLASS_TIME",  "CLASS_TYPE", "ROOMNUM") 
          VALUES (p_class, p_unitc, p_classd, p_classt, p_classtp, p_roomnm);
          COMMIT;
        END IF;

        EXCEPTION
          WHEN exc_*** THEN
             DBMS_OUTPUT.PUT_LINE('There is a class ***');

    END OPEN_CLASS;

【讨论】:

【参考方案2】:

我在检查中使用和 + 或首先检查课程 + 日期冲突,然后检查时间/日期/房间冲突。似乎现在可以工作了。

BEGIN
        -- checks
        SELECT nvl((SELECT 1 FROM TUTPRAC WHERE UNITCODE = p_unitc and CLASS_DAY = p_classd or CLASS_DAY = p_classd and CLASS_TIME = p_classt and ROOMNUM = p_roomnm) , 0) INTO x FROM dual;
        SELECT nvl((SELECT 1 FROM UNITSTREAM WHERE UNITCODE = p_unitc and DAY = p_classd or DAY = p_classd and TIME = p_classt and LOCATION = p_roomnm) , 0) INTO y FROM dual;

        -- insert
        IF (x = 0 and y = 0) THEN
          INSERT INTO TUTPRAC (CLASSID, UNITCODE, CLASS_DAY, CLASS_TIME, CLASS_TYPE, ROOMNUM) 
          VALUES (p_class, p_unitc, p_classd, p_classt, p_classtp, p_roomnm);
        END IF;

    END OPEN_CLASS;

【讨论】:

以上是关于PL/SQL 代码不向表中插入记录的主要内容,如果未能解决你的问题,请参考以下文章

pl/sql-create trigger on a table - 每当在同一个表中插入新记录时,应更新表的另一列

基于变化表中的值在插入之前触发 PL/SQL 触发器

PL/SQL-如何使用游标的所有列插入表

如何使用 Form Builder 和 PL/SQL 插入记录?

如何使用触发器在同一张表中插入新行(Oracle PL/SQL 10G)?

使用 Record 插入数据 PL/SQL