触发更新一年中的一周
Trigger to update week of the year
我想写一个触发器,以便在插入或更新 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
你做错了几件事,从日期处理开始。您的 decom_date
列应定义为 DATE
列 - 看起来它可能是示例输出中的字符串。但是您对 sysdate
的处理也是错误的,因为您隐式转换为字符串以便将其转换回日期,这既没有意义又容易出错,因为这可能发生在具有不同的会话中NLS 设置。如果您的专栏实际上是 DATE
那么您也不应该针对它调用 to_date()
;如果它是一个字符串,那么该转换是有效的,但它 应该 是 DATE
.
然后您的触发器正在查询并尝试更新触发器所针对的 table。没有数据不会出错但不会执行任何操作,因为没有要更新的现有行 - 您要插入的行尚不存在。如果有数据,你会得到一个变异 table 错误,如果你没有从 select
部分得到太多行异常。
行级触发器可以访问 NEW
and OLD
pseudorecords 以查看和操作受影响的行;您不需要(通常也不能)使用 DML 查询来访问您正在操作的行中的数据。
如果您的 table 是用日期列和数字列定义的:
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
我想写一个触发器,以便在插入或更新 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
你做错了几件事,从日期处理开始。您的 decom_date
列应定义为 DATE
列 - 看起来它可能是示例输出中的字符串。但是您对 sysdate
的处理也是错误的,因为您隐式转换为字符串以便将其转换回日期,这既没有意义又容易出错,因为这可能发生在具有不同的会话中NLS 设置。如果您的专栏实际上是 DATE
那么您也不应该针对它调用 to_date()
;如果它是一个字符串,那么该转换是有效的,但它 应该 是 DATE
.
然后您的触发器正在查询并尝试更新触发器所针对的 table。没有数据不会出错但不会执行任何操作,因为没有要更新的现有行 - 您要插入的行尚不存在。如果有数据,你会得到一个变异 table 错误,如果你没有从 select
部分得到太多行异常。
行级触发器可以访问 NEW
and OLD
pseudorecords 以查看和操作受影响的行;您不需要(通常也不能)使用 DML 查询来访问您正在操作的行中的数据。
如果您的 table 是用日期列和数字列定义的:
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