【问题标题】:Writing a Trigger to find and fill the age of a patient whenever a patient record is inserted into patients table每当将患者记录插入患者表时,编写触发器以查找并填写患者的年龄
【发布时间】:2020-10-21 16:31:32
【问题描述】:

在这个问题中,我必须在触发器的帮助下添加年龄值。 请帮我解决这个问题。

create or replace trigger ia_patient
after insert on patient
for each row
enable
declare
age_value number(10);
begin
DBMS_OUTPUT.PUT_LINE('Please Insert Age');
update patient set age=&age_value where ??;
end;

我不确定在“哪里”之后应该写什么

【问题讨论】:

  • PATIENT 表是否有名为 DATE_OF_BIRTH 或类似的列?尽管这似乎不太适合触发器使用。换句话说,一个经典的家庭作业。

标签: sql oracle plsql triggers


【解决方案1】:

除非是家庭作业问题,否则真的没有多大意义,因为“年龄”取决于当前日期。

不管怎样,看看这是否有帮助。

SQL> create table patient
  2    (id               number primary key,
  3     date_of_birth    date,
  4     age              number
  5    );

Table created.

触发器:计算年龄为 sysdate 和出生日期之间的月份除以 12(因为一年有 12 个月);当然,这只是一个近似值,但是——据我所知——你的任务不是正确计算年龄,而是学习如何使用触发器。

SQL> create or replace trigger ia_patient
  2    before insert on patient
  3    for each row
  4  begin
  5    :new.age := round(months_between(sysdate, :new.date_of_birth) / 12);
  6  end;
  7  /

Trigger created.

测试:

SQL> insert into patient (id, date_of_birth) values (2, date '2000-10-05');

1 row created.

SQL> select * from patient;

        ID DATE_OF_BI        AGE
---------- ---------- ----------
         2 2000-10-05         20

SQL>

【讨论】:

    【解决方案2】:

    这是对问题的框架挑战。

    不要使用触发器;如果您这样做,它将不时地插入年龄,或者在 6 个月或一年之后,该人将过生日,并且您的表格将不正确。这应该是您在需要数据时在查询中计算出来的,并且可以放入视图中。

    CREATE TABLE people (
      id            INTEGER
                    GENERATED AS IDENTITY
                    CONSTRAINT people__id__pk PRIMARY KEY,
      name          VARCHAR2(50)
                    NOT NULL,
      date_of_birth DATE
                    NOT NULL
    );
    

    然后你可以创建一个视图来计算年龄:

    CREATE VIEW people_ages ( id, name, date_of_birth, age ) AS
    SELECT id,
           name,
           date_of_birth,
           FLOOR( MONTHS_BETWEEN( SYSDATE, date_of_birth ) / 12 )
    FROM   people;
    

    如果你有样本数据:

    INSERT INTO people ( name, date_of_birth )
    SELECT 'Alice', DATE '1970-01-01' FROM DUAL UNION ALL
    SELECT 'Bob',   DATE '2020-10-21' FROM DUAL UNION ALL
    SELECT 'Carol', DATE '2000-10-21' FROM DUAL;
    

    那么视图的输出将是:

    SELECT * FROM people_ages;
    
    身份证 |姓名 | DATE_OF_BIRTH |年龄 -: | :---- | :----------------- | --: 1 |爱丽丝 | 1970-01-01 00:00:00 | 50 2 |鲍勃 | 2020-10-21 00:00:00 | 0 3 |卡罗尔 | 2000-10-21 00:00:00 | 20

    db小提琴here

    【讨论】:

      【解决方案3】:

      您的触发器存在严重缺陷。尽管完全不恰当地使用了触发器,但我会仔细检查它们。

      1. 属性:年龄。可以说其他人已经充分涵盖了它。但我会回到它。
      2. DBMS_OUTPUT:发出时不是输出。 pl/sql 引擎甚至根本不输出这个。它构建了一个内部缓冲区,稍后可以在 pl/sql 完成后由客户端读取和处理。但是,并不要求客户这样做。通常用于调试目的,在生产系统中不可用。
      3. &age_value:这是一种交互式处理的尝试。 pl/sql 不是也不能进行交互式处理。这称为替代变量,完全由客户负责。客户端看到 &... 并提示输入值。然后它会物理地更改语句以包含该值。例如,如果您对提示回复 42,则发送到编译器的内容是 age=42。编译器实际上永远不会看到 &age_value。
      4. 更新:您不能这样做;它会抛出异常“ORA-04091: table ... is mutating, trigger/function may not see it”。在触发器中,您不能对导致触发器触发的表发出 DML。此外,这是完全没有必要的。
      5. where ??:因为您不能拥有更新语句,所以这没有实际意义。

        在触发器中,您通过 pesudo 行 :new 和/或 :old 引用表列。因此,假设您需要使用您重写为的触发器(以下假设插入了 date_of_birth 列(dob)名称):
      create or replace trigger ia_patient
        after insert on patient
        for each row
        enable
      begin
         :new.age := trunc(months_between(sysdate, :new.dob)/12);
      end;
      

      但是,年龄问题现在是一个静态值。这需要定期更新以保持最新状态。更好的方法是让 Oracle 在需要时使用 @MT0 建议的视图进行计算,然后完全放弃触发器。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-14
        • 2014-07-27
        • 1970-01-01
        • 2021-12-30
        相关资源
        最近更新 更多