触发更新一年中的一周

时间:2017-07-13 14:04:18

标签: oracle plsql oracle11g triggers database-trigger

我想编写一个触发器,以便在插入或更新decom_date时,将一年中的一周更新为相应的值。

这是我到目前为止所做的,但在插入日期后,本周仍为空。

create or replace trigger test_trigger
before insert on check_decom
for each row
begin
if inserting then
update check_decom set decom_week= (select to_char(to_date(decom_date,'DD-
MON-YY'),'WW') as week from check_decom) ;
end if;
end;
/

SQL> select * from check_decom;

DECOM_DATE                     DECOM_WEEK
------------------------------ ----------
23-JUN-17

我做错了什么?

一年中的一周的例子

SQL> select to_char(to_date(sysdate,'DD-MON-YY'),'WW') as week from dual;
WE
--
28

1 个答案:

答案 0 :(得分:2)

从日期处理开始,你做了一些错事。您的decom_date列应定义为DATE列 - 它看起来可能是您的示例输出中的字符串。但是你对sysdate的处理也是错误的,因为你隐式转换为一个字符串,以便将它转换回一个日期,这是毫无意义的,容易出错,因为这可能发生在一个不同的会话中NLS设置。如果您的列实际上是DATE,那么您也不应该针对该列调用to_date();如果它是一个字符串,那么该转换是有效的,但 应该是DATE

然后您的触发器正在查询并尝试更新触发器所针对的表。没有数据没有错误但没有做任何事情因为没有要更新的现有行 - 您插入的那个尚不存在。如果有数据,那么如果您没有从select部分获得太多行异常,则会出现变异表错误。

行级触发器可以访问NEW and OLD pseudorecords以查看和操纵受影响的行;您不需要(通常不能)使用DML查询来访问您正在操作的行中的数据。

如果您的表定义了日期列和数字列:

create table check_decom(decom_date date, decom_week number);

然后你的触发器可能看起来像:

create or replace trigger test_trigger
before insert on check_decom
for each row
begin
  if inserting then
    :new.decom_week := to_number(to_char(:new.decom_date, 'WW'));
  end if;
end;
/

尽管if inserting检查有点无意义,因为触发器只会在插入时触发。这本身可能是一个问题;您可能也希望将其设置为更新,但逻辑相同,因此将是:

create or replace trigger test_trigger
before insert or update on check_decom
for each row
begin
  :new.decom_week := to_number(to_char(:new.decom_date, 'WW'));
end;
/

做你想做的事:

insert into check_decom (decom_date) values (date '2017-06-23');

1 row inserted.

select * from check_decom;

DECOM_DAT DECOM_WEEK
--------- ----------
23-JUN-17         25

但我根本不会用触发器来做这件事。从Oracle 11g开始,您可以使用a virtual column代替:

create table check_decom (
  decom_date date,
  decom_week generated always as (to_number(to_char(decom_date, 'WW')))
);

Table CHECK_DECOM created.

insert into check_decom (decom_date) values (date '2017-06-23');

1 row inserted.

select * from check_decom;

DECOM_DAT DECOM_WEEK
--------- ----------
23-JUN-17         25