Oracle 从其他列计算结果中更新列

Oracle Update Column From Other Column Calculation Result

我有一个 table passenger 具有以下结构。

CREATE TABLE passenger (
  id NUMERIC(12,0) NOT NULL,
  station VARCHAR(3), 
  adult NUMERIC(3,0), 
  child NUMERIC(3,0), 
  infant NUMERIC(3,0),
  crew NUMERIC(3,0) DEFAULT 0,
  paying NUMERIC(4,0), 
  non_paying NUMERIC(4,0),  
  total_passenger NUMERIC(3,0), 
  PRIMARY KEY (id)
);

初始记录如下

id  | station | adult | child | infant | crew | paying | non_paying | total_passenger
100 | GWN     | 20    | 4     | 1      | 2    | 24     | 3          | 27

paying 字段的值是通过将 adultchild 值相加计算得出的。而且,通过对 infantcrew 求和,我可以获得 non_paying 值。然后我可以对 payingnon_paying 字段求和以获得 total_passenger.

问题是,当我用每个字段可能的 NULL 值更新 adultchildinfantcrew 字段时,数据库可以重新计算 payingnon_payingtotal_passenger 而无需手动更新它们吗?

我尝试了以下查询但结果出乎意料。

UPDATE passenger
SET adult = NVL(NULL, adult),
    child = NVL(6, child),
    infant = NVL(3, infant),
    crew = NVL(NULL, crew),
    paying = adult + child,
    non_paying = infant + crew,
    total_passenger = paying + non_paying
WHERE id = 100;

NULL关键字来自prepared statement参数,可能为null值。如何自动更新最后三个字段?

您可以使用触发器在 UPDATE 发生后对 passenger table 进行额外更新:

CREATE OR REPLACE TRIGGER update_passenger
AFTER UPDATE OF passenger
FOR EACH ROW
BEGIN
   UPDATE passenger
   SET
       paying = NVL(:NEW.adult, 0) + NVL(:NEW.child, 0),
       non_paying = NVL(:NEW.infant, 0) + NVL(:NEW.crew, 0),
       total_passenger = NVL(:NEW.adult, 0) + NVL(:NEW.child, 0) +
                         NVL(:NEW.infant, 0) + NVL(:NEW.crew, 0)
END;

要使用触发器,您只需照常更新 passenger。如果您将给定记录的 adultchildinfantcrew 字段更新为 NULL,那么我的触发器将处理 NULL 作为 0 在总计的计算中。

如果您使用的是 oracle 11g 以上版本,请考虑使用虚拟列。

create table passenger(id numeric(12, 0) not null,
                       station varchar2(3),
                       adult           numeric(3, 0) default 0,
                       child           numeric(3, 0) default 0,
                       infant          numeric(3, 0) default 0,
                       crew            numeric(3, 0) default 0,
                       paying numeric(4, 0) generated always
                       as(adult + child) virtual,
                       non_paying numeric(4, 0) generated always
                       as(infant + crew) virtual,
                       total_passenger NUMERIC(3, 0) generated always
                       as(adult + child + infant + crew) virtual,
                       primary key(id));

insert into passenger
  (id, station, adult, child, infant, crew)
values
  (1, '1', 2, 3, 4, 5);
insert into passenger (id, station, child, crew) values (2, '2', 7, 8);

select * from passenger;

/*
ID  STATION ADULT CHILD INFANT  CREW  PAYING  NON_PAYING  TOTAL_PASSENGER
1   1       2     3     4       5     5       9           14
2   2       0     7     0       8     7       8           15
*/