Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oracle 甲骨文:需要关于触发器的帮助吗_Oracle_Oracle Sqldeveloper - Fatal编程技术网

Oracle 甲骨文:需要关于触发器的帮助吗

Oracle 甲骨文:需要关于触发器的帮助吗,oracle,oracle-sqldeveloper,Oracle,Oracle Sqldeveloper,大家好,又是我,我刚开始学习Oracle/数据库学位课程,几天前我发布了这篇文章,得到了及时的回复,非常感谢 在此之后,考虑一下我有这2个表 CREATE TABLE CUSTOMER ( CustID NUMBER(5) NOT NULL, CONSTRAINT CustID_PK PRIMARY KEY (CustID), PlanTypeNo Number(1) NOT NULL, CONSTRAINT PlanTypeNo_CustomerFK

大家好,又是我,我刚开始学习Oracle/数据库学位课程,几天前我发布了这篇文章,得到了及时的回复,非常感谢

在此之后,考虑一下我有这2个表

CREATE TABLE CUSTOMER (
    CustID NUMBER(5) NOT NULL,
    CONSTRAINT CustID_PK PRIMARY KEY (CustID),
    
    PlanTypeNo Number(1) NOT NULL,
    CONSTRAINT PlanTypeNo_CustomerFK FOREIGN KEY (PlanTypeNo) REFERENCES PLANTYPE(PlanTypeNo),
    
    CustName VARCHAR2(50) NOT NULL,
    CustICNo VARCHAR2(9) NOT NULL,
    CustTelNo VARCHAR2(8) NOT NULL,
    CONSTRAINT UniqueCustomer UNIQUE (CustICNo,CustTelNo),
    CONSTRAINT Exact_IC_Length CHECK (LENGTH(CustICNo) = 9),
    CONSTRAINT Exact_Tel_Length CHECK (LENGTH(CustTelNo) = 8),
    
    PaymentModePref VARCHAR2(15) NOT NULL,
    CONSTRAINT PaymentModePref_Accepted CHECK (PaymentModePref IN ('Paypal','Cash','EFT')),
    
    LastBillPaidDate DATE,
    hasUnpaidBill NUMBER(1) NOT NULL,
    CONSTRAINT UnpaidBill_Boolean CHECK (hasUnpaidBill IN ('0', '1')),
    
    CompanyName VARCHAR2(50),
    CompanyRegNo VARCHAR2(10),
    CONSTRAINT If_NonResident CHECK ((((PlanTypeNo) = 1) OR (CompanyName IS NOT NULL AND CompanyRegNo IS NOT NULL)))
    
    
);

我对编码比较有经验,但对数据库程序/脚本编写/查询没有经验。您将如何创建一个路径约束?让数据库检查有未付账单的所有者是否要添加新位置

我还比较了CustID外键,返回到CUSTOMER表,检查是否有大于60天的LastBillPaidDate,或者如果当前日期-LastBillPaidDate>60,则创建一个触发器将hasUnpaidBill变为“1”,然后在尝试插入行时检查hasUnpaidBill的值是否为1

希望不要太混乱,我了解逻辑,但不知道如何在数据库中实现它:|


再次感谢

下面是一个触发器示例。在编写触发器时,可以查询其他表,但通常不能查询正在插入/更新的表。所以可以查询CUSTOMER,但您应该使用来引用当前插入的位置记录上的字段

set define off
CREATE OR REPLACE TRIGGER LOCATION.LOC_CUSTOMER_UNPAID
BEFORE INSERT 
FOR EACH ROW
DECLARE
    has_unpaid varchar2(1);
    unpaid_bill EXCEPTION;
    PRAGMA EXCEPTION_INIT( unpaid_bill, -20001 );
BEGIN

    select 'Y' into has_unpaid
    from CUSTOMER c
    where c.CustID = :new.CustID
      and lastBillPaidDate < sysdate-60;
    
    if has_unpaid = 'Y' then
        raise_application_error( -20001, 'Cannot create new location: Customer has unpaid bill.' );
    end if;
    
EXCEPTION when NO_DATA_FOUND then
    null; -- ignore
END;
/
set define off并不是严格必需的,但是一些IDE会感到困惑,并要求您为:NEW设置一个值作为绑定变量

我想说,数据库可能不是这种逻辑的最佳场所。您可以在触发器中执行此操作,但有时会有点尴尬-如果您无法捕获错误并显示友好消息,则从触发器引发错误消息回溯在客户端可能看起来很糟糕

编辑:我来了。这个过程有点复杂。未付账单异常表示我们正在创建一个新的错误类型,PRAGMA异常表示将我们的错误与代码-20001关联,raise\u应用程序\u error-20001表示生成/返回该错误代码

为了提供更多背景信息,如果您想阻止用户在有未付账单的情况下添加位置之类的操作,您有几个选项:

约束适用于验证正在插入的当前行。这通常是简单的逻辑,比如PHONE_NUM中没有字母,或者AGE大于零。如果违反约束逻辑,将引发异常并阻止插入。 也可以使用BEFORE INSERT触发器-如果它引发异常,它将阻止插入。它们比约束更慢、更复杂,而且很难调试,但也很灵活——您可以查询其他表、调用函数等。优秀的程序员会节约使用它们。 使用应用程序逻辑几乎总是您的首选。这是最灵活的选项,通常速度更快,而且您可以向用户显示比Oracle错误堆栈跟踪有用得多的警告。 如果面向用户的应用程序很大且复杂,或者用户具有数据库访问权限,那么API也是一种很好的模式。将所有验证代码写入执行插入的存储过程或包中,并使应用程序/用户调用API,而不是直接插入到表中。您可以通过授予/权限来强制执行此模式,但我在这里不详细介绍。
一些评论。1如果“未付”始终可以由sysdate-LastBillPaidDate的年龄确定,则不需要hasupaidbill列。2 HasUnpaidBill是一个数字,但它的检查约束是匹配字符串。提示:1无引号是数字,“1”引号是字符串。3默认情况下,oracle对象名称不区分大小写。因此,使用CamelCaseObjectName是没有意义的。为了实现视觉上的“可读性”,我们通常使用下划线分隔的对象名称。啊,是的,我想知道命名约定是什么,因为Oracle不关心大小写。好的,关于sysdate-lastbillpaiddate,在LOCATION表中写入约束时,有没有方法引用CUSTOMER表?您将如何编写一个约束以适应该场景?非常感谢!你想要什么样的约束?通常,交叉表约束(我的术语,刚编好的)将是外键,您已经有了外键。您好,基本上,您将如何创建一种方法,让数据库检查在过去60天内有未付账单的所有者是否希望使用其CustID作为外键添加新位置?抱歉,回复太晚了,被任务淹没了。代码看起来很好,可以理解,只是为了某种任务/测试,所以想尝试一下如何工作我还处于使用DMB的新手级别,所以我不确定它们的约束条件/良好实践你能解释什么是PRAGMA以及为什么未付账单是例外吗?
set define off
CREATE OR REPLACE TRIGGER LOCATION.LOC_CUSTOMER_UNPAID
BEFORE INSERT 
FOR EACH ROW
DECLARE
    has_unpaid varchar2(1);
    unpaid_bill EXCEPTION;
    PRAGMA EXCEPTION_INIT( unpaid_bill, -20001 );
BEGIN

    select 'Y' into has_unpaid
    from CUSTOMER c
    where c.CustID = :new.CustID
      and lastBillPaidDate < sysdate-60;
    
    if has_unpaid = 'Y' then
        raise_application_error( -20001, 'Cannot create new location: Customer has unpaid bill.' );
    end if;
    
EXCEPTION when NO_DATA_FOUND then
    null; -- ignore
END;
/