我正在尝试在Oracle 12c数据库表中执行批量数据更新,以获取与一系列日期匹配的记录。日期有时间信息,所以我使用trunc()
函数去掉时间组件。我可以使用此条件成功执行选择查询,但以某种方式使用相同的where子句进行更新与记录不匹配。任何人都知道发生了什么?
select count(*) from TABLE_NAME
where TRUNC(DATE_FIELD) in ('30-Apr-13', '31-May-13', '31-Jul-13')
-- 554
然而..
update TABLE_NAME set SOME_FIELD = 'VALUE'
where TRUNC(DATE_FIELD) in ('30-Apr-13', '31-May-13', '31-Jul-13')
-- 0 rows updated.
- 编辑 -
我也尝试to_date('30-Apr-13'), ...
无效。
答案 0 :(得分:2)
原始问题中没有明确规定,但您依靠日期和字符串之间的隐式转换,以及通过NLS_DATE_FORMAT
在不同默认格式的会话中运行查询和更新设置。要复制效果:
create table table_name (date_field date, some_field varchar2(5));
insert into table_name values (timestamp '2013-04-30 00:00:01', null);
alter session set nls_date_format = 'DD-MON-RR';
select count(*) from TABLE_NAME
where TRUNC(DATE_FIELD) in ('30-Apr-13', '31-May-13', '31-Jul-13');
COUNT(*)
----------
1
alter session set nls_date_format = 'DD-MON-YYYY';
update TABLE_NAME set SOME_FIELD = 'VALUE'
where TRUNC(DATE_FIELD) in ('30-Apr-13', '31-May-13', '31-Jul-13');
0 rows updated.
隐式转化正在将截断日期列值更改为,例如'30-Apr-2013'
,这与您与'30-Apr-13'
进行比较的文字不匹配。使用您作为修改添加的版本,比较to_date('30-Apr-13')
,将转换为日期0013-04-30
,但仍然与日期2013-04-30
不匹配。
您仍然可以使用字符串比较,但提供四位数的年份代表:
update TABLE_NAME set SOME_FIELD = 'VALUE'
where TRUNC(DATE_FIELD) in ('30-Apr-2013', '31-May-2013', '31-Jul-2013');
1 row updated.
将字符串转换为带有显式格式掩码的日期通常会更好(四位数年份更好,但如果您为此做好准备,可以使用两位数字歧义的风险):
update TABLE_NAME set SOME_FIELD = 'VALUE'
where TRUNC(DATE_FIELD) in (to_date('30-Apr-2013', 'DD-Mon-YYYY'),
to_date('31-May-2013', 'DD-Mon-YYYY'), to_date('31-Jul-2013', 'DD-Mon-YYYY'));
1 row updated.
update TABLE_NAME set SOME_FIELD = 'VALUE'
where TRUNC(DATE_FIELD) in (to_date('30-Apr-13', 'DD-Mon-RR'),
to_date('31-May-13', 'DD-Mon-RR'), to_date('31-Jul-13', 'DD-Mon-RR'));
1 row updated.
或者因为它们是固定日期,您可以使用更短但无明确的date literals:
update TABLE_NAME set SOME_FIELD = 'VALUE'
where TRUNC(DATE_FIELD) in (date '2013-04-30', date '2013-05-31', date '2013-07-31');
1 row updated.
值得指出的是,执行TRUNC(DATE_FIELD)
将阻止使用该列的任何索引,无论您将其与之比较。您可以与日期范围进行比较,以避免这种情况,例如:
update TABLE_NAME set SOME_FIELD = 'VALUE'
where (DATE_FIELD >= date '2013-04-30' and DATE_FIELD < date '2013-05-01')
or (DATE_FIELD >= date '2013-05-31' and DATE_FIELD < date '2013-06-01')
or (DATE_FIELD >= date '2013-07-31' and DATE_FIELD < date '2013-08-01');
答案 1 :(得分:1)
使用ANSI date literals而不是依靠NLS_DATE_FORMAT parameter将字符串转换为日期:
UPDATE table_name
SET some_field = 'VALUE'
WHERE TRUNC( date_field ) IN ( DATE '2013-04-30', DATE '2013-05-31', DATE '2014-07-31' )