【问题标题】:Oracle day of week (without string comparison) [duplicate]Oracle 星期几(没有字符串比较)[重复]
【发布时间】:2018-08-08 16:12:08
【问题描述】:

我会先说我发现的所有文档都不适用于我的 oracle 版本: https://docs.oracle.com/cd/E51711_01/DR/WeekDay.html; https://docs.oracle.com/cd/E37483_01/server.751/es_eql/src/ceql_functions_date_extract.html

或者我可以使用的功能参考没有提到星期几: https://docs.oracle.com/cd/B28359_01/server.111/b28286/functions052.htm#SQLRF00639

所以我只是想办法使用to_char 然后进行 varchar2 比较。如果可能的话,我只想坚持日期格式。

这是我目前的 sql

select dateSold from sales
where extract(dateSold, day_of_week) in (1, 3, 4, 7)

SQL Error: ORA-00904: "DAY_OF_WEEK": invalid identifier

【问题讨论】:

  • 第一个链接用于文档自动化语言 (DAL)。第二个链接适用于 Oracle Endeca Server。 (我从未听说过其中任何一个)。 Oracle 在同一个站点上拥有其所有产品的文档,这在搜索内容时可能会有些混乱,但您应该只参考 RDBMS 文档,如您的第三个链接中的 11gR1 - 使用 DB 版本的文档你正在努力。 This might be a useful place to start 因为您可以从下拉列表中选择正确的版本。

标签: sql oracle oracle11g


【解决方案1】:

您需要使用to_char() 来获取日期编号,但您可以将其转换为数字:

select dateSold, sum(quantity) from sales
where to_number(to_char(dateSold, 'D')) in (1, 3, 4, 7)

但是D 是依赖于 NLS 的,因此如果您在美国与法国的会话中运行它,您会得到不同的结果。这可能就是您看到字符串比较的原因,因为您至少可以控制更多:

select dateSold, sum(quantity) from sales
where to_char(dateSold, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH') in ('MON', 'WED', 'THU', 'SUN')

要查看 NLS 设置的不同之处,这会显示相同数据和查询的 DDY 值,就像在美国运行一样:

alter session set nls_territory = 'AMERICA';
alter session set nls_language = 'ENGLISH';

with cte (dateSold) as (
  select date '2018-08-01' + level - 1 from dual connect by level <= 7
)
select dateSold,
  to_number(to_char(dateSold, 'D')) as d,
  to_char(dateSold, 'DY') as dy,
  to_char(dateSold, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH') as dy_english
from cte;

DATESOLD           D DY           DY_ENGLISH  
--------- ---------- ------------ ------------
01-AUG-18          4 WED          WED         
02-AUG-18          5 THU          THU         
03-AUG-18          6 FRI          FRI         
04-AUG-18          7 SAT          SAT         
05-AUG-18          1 SUN          SUN         
06-AUG-18          2 MON          MON         
07-AUG-18          3 TUE          TUE         

然后就像在法国跑步:

alter session set nls_territory = 'FRANCE';
alter session set nls_language = 'FRENCH';

with cte (dateSold) as (
  select date '2018-08-01' + level - 1 from dual connect by level <= 7
)
select dateSold,
  to_number(to_char(dateSold, 'D')) as d,
  to_char(dateSold, 'DY') as dy,
  to_char(dateSold, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH') as dy_english
from cte;

and the same thing as if run in the USA:

DATESOLD          D DY               DY_ENGLISH  
-------- ---------- ---------------- ------------
01/08/18          3 MER.             WED         
02/08/18          4 JEU.             THU         
03/08/18          5 VEN.             FRI         
04/08/18          6 SAM.             SAT         
05/08/18          7 DIM.             SUN         
06/08/18          1 LUN.             MON         
07/08/18          2 MAR.             TUE         

请注意,日期编号和名称/缩写完全不同,因此尝试将它们与固定值进行比较 - 无论是 in (1, 3, 4, 7) 还是使用字符串文字日期名称 - 都不会可靠地匹配。

将日期语言强制为英语使比较安全。 (当然,或者任何其他语言 - 字符串文字值只需与您为 to_char() 的第三个参数选择的语言匹配。)

【讨论】:

  • 那么如果不更改为varchar2就没有办法做到这一点吗?你有什么暗示为什么甲骨文会改变他们过去的做法吗?
  • 这就是他们一直以来的做法。可悲的是,没有 NLS 安全的天数。我不相信有办法不使用字符串,不。
  • 嗯...您可以从您知道是一周中的特定日期的固定日期中减去您的日期,然后将其修改为 7,这将为您提供一个数字从 0 到 6。然后根据需要进行解释。不过,这似乎比字符串比较更有效......
  • 我已经这样做来寻找感恩节了。如果你知道更好的方法来找到它会很棒
  • @UpTide - 不确定你现在在做什么,完全跑题了;但是(美国)今年的感恩节是:next_day(add_months(trunc(sysdate, 'YYYY'), 10) + 20, 'THURSDAY')。对于任何其他年份(从 1942 年开始),将 trunc(sysdate, 'YYYY') 替换为该年的第一天。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-30
  • 2022-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-24
相关资源
最近更新 更多