Oracle日期匹配

时间:2016-09-05 10:17:59

标签: sql oracle date

我正在尝试在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'), ...无效。

2 个答案:

答案 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' )