甲骨文(或非)工作日会议

时间:2016-06-13 16:05:50

标签: sql oracle11g

我已经为我的同事编写了一个查询,其中涉及在给定日期从Oracle Express g11中提取数据。 查询使用的日期是上一个工作日(昨天或星期五)。

出于某种原因,同一查询会返回不同的数字来表示星期几。

示例:

SELECT TRUNC('13June2016') - TRUNC('13June2016', 'D')
FROM DUAL

在我的计算机上运行时,此查询返回0,但在我的同事的计算机上,它返回1。这种情况发生在我们可用的每个SQL客户端/接口上。

据我所知,我们在数据库中的计算机和用户设置相同,但显然有些设置已关闭。

坦率地说,我试图谷歌在哪里出现这种差异,但我收到了很多无关的结果。我迷路了,因为我甚至不知道在哪里寻找可以解释这种差异的设置(或者不确定)。

1 个答案:

答案 0 :(得分:1)

D格式修饰符依赖于会话的NLS设置:

alter session set nls_territory = 'America';
alter session set nls_date_format = 'YYYY-MM-DD';

select to_char(date '2016-06-13', 'D') char_d,
  trunc(date '2016-06-13', 'D') trunc_d,
  date '2016-06-13' - trunc(date '2016-06-13', 'D') diff1,
  trunc(sysdate) - trunc(sysdate, 'D') diff2
from dual;

C TRUNC_D         DIFF1      DIFF2
- ---------- ---------- ----------
2 2016-06-12          1          1

alter session set nls_territory = 'United Kingdom';
alter session set nls_date_format = 'YYYY-MM-DD';

select to_char(date '2016-06-13', 'D') char_d,
  trunc(date '2016-06-13', 'D') trunc_d,
  date '2016-06-13' - trunc(date '2016-06-13', 'D') diff1,
  trunc(sysdate) - trunc(sysdate, 'D') diff2
from dual;

C TRUNC_D         DIFF1      DIFF2
- ---------- ---------- ----------
1 2016-06-13          0          0

(有趣的是,我在使用trunc(date '2016-06-13')时偶然发现错误14073795;截断是多余的,看起来非常不一致 - 更改列别名会使其显示或消失 - 所以我认为它不相关到你所看到的。)

因此,您和您的同事似乎将您的PC放在不同的区域设置中,并且您测试的客户端继承了区域设置或以不同方式明确设置区域。

要获得一致的结果,无论语言环境/ NLS设置如何,您都可以使用the 'IW' format element instead of 'D',因为这样做:

  

与ISO 8601标准(即星期一)定义的日历周的第一天相同的一周

alter session set nls_territory = 'America';
alter session set nls_date_format = 'YYYY-MM-DD';

select to_char(date '2016-06-13', 'IW') char_iw,
  trunc(date '2016-06-13', 'IW') trunc_iw,
  date '2016-06-13' - trunc(date '2016-06-13', 'IW') diff1,
  trunc(sysdate) - trunc(sysdate, 'IW') diff2
from dual;

CH TRUNC_IW        DIFF1      DIFF2
-- ---------- ---------- ----------
24 2016-06-13          0          0

alter session set nls_territory = 'United Kingdom';
alter session set nls_date_format = 'YYYY-MM-DD';

select to_char(date '2016-06-13', 'IW') char_iw,
  trunc(date '2016-06-13', 'IW') trunc_iw,
  date '2016-06-13' - trunc(date '2016-06-13', 'IW') diff1,
  trunc(sysdate) - trunc(sysdate, 'IW') diff2
from dual;

CH TRUNC_IW        DIFF1      DIFF2
-- ---------- ---------- ----------
24 2016-06-13          0          0

您可以详细了解how the format models are used in trunc() and round() functions,更一般地了解date format models

依赖隐式转换也不是一个好主意; TRUNC('13June2016', 'D')使用会话的NLS_DATE_FORMAT设置隐式将字符串'13June2016'转换为日期。在具有不同设置的会话中运行该错误。并且TRUNC('13June2016')是多余的,因为隐式转换的日期已经将其时间设置为午夜,如果它没有错误。

您应该始终显式转换字符串并指定格式模型,例如TRUNC(TO_DATE('13June2016', 'DDMonthYYYY', 'NLS_DATE_LANGUAGE=ENGLISH'), 'D')(如果会话日期语言是其他内容,则需要第三个参数,这将停止6月被识别;或者更简单地使用ISO日期文字,如DATE '2016-06-13'。您可能正在使用日期时间当然,你的真实代码中的变量。