【问题标题】:Creating a simple Oracle SQl trigger创建一个简单的 Oracle SQL 触发器
【发布时间】:2015-12-20 03:42:51
【问题描述】:

我正在尝试为假数据库创建触发器。假设那里 是 BANK-BRANCH 的一个名为“total_loan”的派生属性,用于维护每个分行的贷款总额。我正在尝试设计一个触发器来维护这个派生属性。因此,我的触发器似乎停止了我的 load.sql 脚本,如下所示:

CREATE TABLE a2_bankbranch (
name           VARCHAR(200)  NOT NULL,
branch_num     VARCHAR(200)  NOT NULL,
address        VARCHAR(200)  NOT NULL,
routing_code   VARCHAR(200)  NOT NULL,
total_loan     NUMBER(38),
FOREIGN KEY(routing_code) REFERENCES a2_bank(routingcode),
PRIMARY KEY(branch_num, routing_code)
);
@trig.sql

INSERT INTO a2_bankbranch VALUES
( 'ASB', '5', '3 gladstone rd', '123456', '');
INSERT INTO a2_bankbranch VALUES
( 'ASB', '4', '28 stevee rd', '123456', '');

CREATE TABLE a2_loan (
loan_num       CHAR(10)  PRIMARY KEY,
type           VARCHAR(200)  NOT NULL,
amount         NUMBER(38)  NOT NULL,
contract_date  DATE          NOT NULL,
branch_num     VARCHAR(200) NOT NULL,
routing_code   VARCHAR(200) NOT NULL,
FOREIGN KEY(routing_code) REFERENCES a2_bank(routing_code),
Foreign KEY(branch_num) REFERENCES a2_bankbranch(branch_num)
);

INSERT INTO a2_loan VALUES
( '323', 'Mortgage', '2000000', TO_DATE('11-03-1994', 'DD-MM-YYYY'), '5', '123456');
INSERT INTO a2_loan VALUES
( '33', 'Car', '2000', TO_DATE('12-08-1994', 'DD-MM-YYYY'), '5', '123456' );
INSERT INTO a2_loan VALUES
( '3243', 'Pesonal', '875', TO_DATE('14-06-1994', 'DD-MM-YYYY'), '5', '123456' );
INSERT INTO a2_loan VALUES
( '6', 'Mortgage', '400500', TO_DATE('11-06-1994', 'DD-MM-YYYY'), '5', '123456' );

我的触发器如下所示,初始插入不起作用,我不确定在 WHERE 和 SET 行中放入什么来更新和删除 trig.sql如下所示

-- Create a trigger that will update the total loan amount
--that each bank brach may have

CREATE OR REPLACE TRIGGER ttl
AFTER INSERT OR UPDATE OR DELETE OF total_loan ON a2-bankbranch
FOR EACH ROW
BEGIN
IF INSERTING THEN
UPDATE a2_loan
SET total_loan = total_loan + :NEW.amount
WHERE branch_num = :NEW.bank_num;
ELSIF UPDATING THEN
UPDATE a2_loan
SET total_loan = total_loan + amount
WHERE
ELSE --deleting
UPDATE a2_loan
WHERE
END;

任何帮助将不胜感激

【问题讨论】:

  • 您已将此标记为 SQL Server 和 Oracle,这两个不同的数据库。您实际使用的是哪一个?我假设甲骨文。我猜应该删除 SQL Server 标记。您的数据类型没有意义——您将数值存储在 varchar2 列中。我希望您希望在 loan 表上定义触发器,但没有明显的方法可以将贷款与数据模型中的分支联系起来。
  • 是的,很抱歉使用 Oracle。如您所见,我有点迷茫,触发器的最终结果应该是,如果我更改特定客户拥有的贷款金额,数据库将自动更新该客户所在的 bank_branch 给出的总贷款金额成员在。这有帮助吗?
  • 您如何知道客户属于哪个分支机构?我在您的数据模型中没有看到任何内容告诉我们如何将贷款或客户映射到分支机构。您是否期望答案需要您发布的所有表格?如果不是这样,将事情缩减到只关注感兴趣的表格会使问题更清楚。
  • 很抱歉,当创建新贷款时,数据库需要更新 bank_branch 属性 total_loan。我将快速编辑代码以仅包含必要的表格
  • 添加loan_num 6 时应该更新哪个a2_bankBranch 行?您的数据模型似乎缺少一种方法来表明特定贷款归特定分支机构所有。我猜您可能希望将branch_numrouting_code 添加到a2_loan 表中,作为a2_bankBranch 的外键来指示这种关系。除非一笔贷款可以申请多个分行。

标签: oracle triggers


【解决方案1】:

首先,标准警告。在现实世界中,你永远不会使用触发器来做这种事情。在现实世界中,您可能一开始就不应该存储非规范化总数。如果你这样做,你会想要使用物化视图来维护它。

话虽如此,我希望你想要类似的东西

CREATE OR REPLACE TRIGGER your_trigger_name
  AFTER INSERT, UPDATE, DELETE ON a2_loan
  FOR EACH ROW
BEGIN
  IF INSERTING 
  THEN
    UPDATE a2_bankbranch
       SET total_loan = nvl(total_loan,0) + :new.amount
     WHERE routing_code = :new.routing_code
       AND branch_num   = :new.branch_num;
  END IF;

  IF UPDATING
  THEN
    UPDATE a2_bankbranch
       SET total_loan = nvl(total_loan,0) - :old.amount
     WHERE routing_code = :old.routing_code
       AND branch_num   = :old.branch_num;

    UPDATE a2_bankbranch
       SET total_loan = nvl(total_loan,0) + :new.amount
     WHERE routing_code = :new.routing_code
       AND branch_num   = :new.branch_num;
  END IF;

  IF DELETING
  THEN
    UPDATE a2_bankbranch
       SET total_loan = nvl(total_loan,0) - :old.amount
     WHERE routing_code = :old.routing_code
       AND branch_num   = :old.branch_num;
  END IF;
END;

【讨论】:

  • 只是为了强调你为什么不使用触发器:Sally 插入了 5 美元的贷款。触发器将分行的总贷款设置为 100 美元至 105 美元。在 Sally 提交她的插入(使其对其他用户可见)之前,Jenny 插入了 10 美元的贷款。 Jenny 的触发器(看不到 Sally 的贷款)将分行贷款总额从 100 美元设置为 110 美元。珍妮承诺。分行总价为 110 美元。片刻之后,莎莉答应了。分行总额变为 105 美元。包括 Sally 和 Jenny 在内的实际贷款总额为 115 美元。
  • @KevinKirkpatrick - 这将是这种触发器的一些潜在实现的问题。这个特定的触发器不会有问题,因为两个会话不能锁定同一行来同时更新它。在这个实现中,Jenny 的会话将阻塞,直到 Sally 的会话提交。问题在于,如果 Sally 的会话因任何原因挂起,则在 DBA 识别并终止会话之前,没有人能够处理该分支的贷款。这可能会严重限制应用程序的可扩展性。
  • 我们都有些不妥:当 Jenny 发出她的插入时,她的更新将被阻止,直到 Sally 提交。 Sally 的承诺将总计更新为 105 美元。一旦 Sally 的提交发出,Jenny 的会话将被解除阻塞。但是,它仍然会错误地设置总数(110 美元而不是 115 美元)。有一些解决方法 - 触发器可以首先选择分支行进行更新(等待对其进行排除锁定),然后发出更新 total_loan = total_loan+:new.amount。重点是 - 触发器变得复杂......即使正确完成(保持数据完整性),也会因锁定而出现可伸缩性问题。
  • 过失。更新仅在锁定清除后读取当前值。你是对的 - 总数已正确更新,唯一的问题是锁定。发帖前没有花 2 分钟检查我的假设是犯下的大罪。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-10
  • 2020-09-08
  • 2018-12-02
相关资源
最近更新 更多