什么是更新行而不需要重新插入的正确 PL/SQL?
What is the right PL/SQL for updating rows without a need to reinsert it?
我刚开始使用 PL/SQL,我想要以下内容:
我在 Oracle SQLcl
上有这个 table
create table Child (
id varchar not null,
name varchar not null,
gender varchar not null,
YearOfBirth number(4) not null,
YearsOfAge number(4) null,
CONSTRAINT Pk primary key (id)
);
我想要一个 PL/SQL(首选匿名),通过从“YearOfBirth”字段中减去 2020 来更新“YearsOfAge”字段。我可以这样做,但我的问题是 table 在我再次插入 PL/SQL 块之前不会更新。因此,每当我插入新行时,我都必须再次插入 PL/SQL 块。我想在 insert/update 行时更新 table,而不需要在新行之后插入此块。
更清楚一点,我只想在创建 table 后插入一次 SL/SQL 块,然后每当我 [=23] 时更新 table 的“YearsOfAge” =]/删除一行。所以当我写“select * from Child;”我需要查看“YearsOfAge”以及从“YearOf Birth”中减去 2020 计算得出的新值。
我目前的PL/SQL如下:
begin
IF INSERTING THEN
update Child set YearsOfAge = 2020 - YearOfBirth;
ELSIF DELETEING THEN
update Child set YearsOfAge = 2020 - YearOfBirth;
ELSE
update Child set YearsOfAge = 2020 - YearOfBirth;
END IF;
END;
/
如果您确实需要以这种方式存储年龄,一些选项是虚拟列、视图和触发器。
虚拟专栏
有了虚拟列,Oracle 将自动即时执行计算。
SQL> create table Child
2 (
3 id number not null,
4 name varchar2(10) not null,
5 gender varchar2(10) not null,
6 YearOfBirth number(4) not null,
7 YearsOfAge number generated always as (2020 - yearOfBirth) null,
8 constraint pk_child primary key (id)
9 );
Table created.
SQL> insert into child(id, name, gender, yearOfBirth) values(1, 'A', 'female' , 1990);
1 row created.
SQL> insert into child(id, name, gender, yearOfBirth) values(2, 'B', 'male' , 2000);
1 row created.
SQL> insert into child(id, name, gender, yearOfBirth) values(3, 'C', 'non-binary', 2010);
1 row created.
SQL> select * from child;
ID NAME GENDER YEAROFBIRTH YEARSOFAGE
---------- ---------- ---------- ----------- ----------
1 A female 1990 30
2 B male 2000 20
3 C non-binary 2010 10
查看
虚拟列的一个缺点是它们不能使用像 SYSDATE
这样的函数,因此必须对年份进行硬编码。有了视图,表达式可以引用 SYSDATE
并且永远是最新的:
create or replace view child_view as
select id, name, gender, yearOfBirth, extract(year from sysdate) - yearOfBirth yearsOfAge
from child;
触发(警告)
您还可以使用触发器在插入或更新行时创建值:
create or replace trigger child_trg
before update or insert on child
for each row
begin
if updating('YEAROFBIRTH') or inserting then
:new.yearsOfAge := extract(year from sysdate) - :new.yearOfBirth;
end if;
end;
/
但在实践中,触发器很难维护。这就引出了一个问题:你为什么要首先存储这些信息?
好的数据库设计应该尽量减少冗余数据量。例外总是有的,但是对于这些例外你应该有一个很好的理由,比如你不希望别人出错的特别复杂的计算,你不能创建一个 PL/SQL 函数因为一个不寻常的安全约束等等。计算像年龄这样琐碎的事情可能会导致比它解决的问题更多的问题。
我刚开始使用 PL/SQL,我想要以下内容: 我在 Oracle SQLcl
上有这个 tablecreate table Child (
id varchar not null,
name varchar not null,
gender varchar not null,
YearOfBirth number(4) not null,
YearsOfAge number(4) null,
CONSTRAINT Pk primary key (id)
);
我想要一个 PL/SQL(首选匿名),通过从“YearOfBirth”字段中减去 2020 来更新“YearsOfAge”字段。我可以这样做,但我的问题是 table 在我再次插入 PL/SQL 块之前不会更新。因此,每当我插入新行时,我都必须再次插入 PL/SQL 块。我想在 insert/update 行时更新 table,而不需要在新行之后插入此块。
更清楚一点,我只想在创建 table 后插入一次 SL/SQL 块,然后每当我 [=23] 时更新 table 的“YearsOfAge” =]/删除一行。所以当我写“select * from Child;”我需要查看“YearsOfAge”以及从“YearOf Birth”中减去 2020 计算得出的新值。 我目前的PL/SQL如下:
begin
IF INSERTING THEN
update Child set YearsOfAge = 2020 - YearOfBirth;
ELSIF DELETEING THEN
update Child set YearsOfAge = 2020 - YearOfBirth;
ELSE
update Child set YearsOfAge = 2020 - YearOfBirth;
END IF;
END;
/
如果您确实需要以这种方式存储年龄,一些选项是虚拟列、视图和触发器。
虚拟专栏
有了虚拟列,Oracle 将自动即时执行计算。
SQL> create table Child
2 (
3 id number not null,
4 name varchar2(10) not null,
5 gender varchar2(10) not null,
6 YearOfBirth number(4) not null,
7 YearsOfAge number generated always as (2020 - yearOfBirth) null,
8 constraint pk_child primary key (id)
9 );
Table created.
SQL> insert into child(id, name, gender, yearOfBirth) values(1, 'A', 'female' , 1990);
1 row created.
SQL> insert into child(id, name, gender, yearOfBirth) values(2, 'B', 'male' , 2000);
1 row created.
SQL> insert into child(id, name, gender, yearOfBirth) values(3, 'C', 'non-binary', 2010);
1 row created.
SQL> select * from child;
ID NAME GENDER YEAROFBIRTH YEARSOFAGE
---------- ---------- ---------- ----------- ----------
1 A female 1990 30
2 B male 2000 20
3 C non-binary 2010 10
查看
虚拟列的一个缺点是它们不能使用像 SYSDATE
这样的函数,因此必须对年份进行硬编码。有了视图,表达式可以引用 SYSDATE
并且永远是最新的:
create or replace view child_view as
select id, name, gender, yearOfBirth, extract(year from sysdate) - yearOfBirth yearsOfAge
from child;
触发(警告)
您还可以使用触发器在插入或更新行时创建值:
create or replace trigger child_trg
before update or insert on child
for each row
begin
if updating('YEAROFBIRTH') or inserting then
:new.yearsOfAge := extract(year from sysdate) - :new.yearOfBirth;
end if;
end;
/
但在实践中,触发器很难维护。这就引出了一个问题:你为什么要首先存储这些信息?
好的数据库设计应该尽量减少冗余数据量。例外总是有的,但是对于这些例外你应该有一个很好的理由,比如你不希望别人出错的特别复杂的计算,你不能创建一个 PL/SQL 函数因为一个不寻常的安全约束等等。计算像年龄这样琐碎的事情可能会导致比它解决的问题更多的问题。