在Oracle SQL中比较日期


141

我试图显示1994年6月20日之后的雇员人数,但是我收到一个错误消息,说“ JUN”无效,请帮忙,谢谢!

Select employee_id, count(*)
From Employee
Where to_char(employee_date_hired, 'DD-MON-YY') > 31-DEC-95; 

1
另请注意,您可以使用> <BETWEEN '' AND ''
Andrew

Answers:


296

31-DEC-95不是字符串,也不是20-JUN-94。它们是数字,最后添加了一些其他内容。这应该是'31-DEC-95''20-JUN-94'-注意单引号,'。这将使您能够进行字符串比较。

但是,您没有在进行字符串比较;您正在进行日期比较。您应该将字符串转换为日期。通过使用内置TO_DATE()函数或日期文字

至今()

select employee_id
  from employee
 where employee_date_hired > to_date('31-DEC-95','DD-MON-YY')

这种方法有一些不必要的陷阱

  • 正如注释中提到的a_horse_with_no_name一样DEC,不一定表示12月。这取决于您NLS_DATE_LANGUAGE和的NLS_DATE_FORMAT设置。为了确保在任何语言环境中工作的比较,你可以使用日期时间格式模型 MM代替
  • 95年是不精确的。您知道您的意思是1995,但是如果是'50,那是1950还是2050?最好总是明确
select employee_id
  from employee
 where employee_date_hired > to_date('31-12-1995','DD-MM-YYYY')

日期文字

日期文字是ANSI标准的一部分,这意味着您不必使用Oracle特定的函数。使用文字时,必须以格式指定日期,YYYY-MM-DD并且不能包含时间元素。

select employee_id
  from employee
 where employee_date_hired > date '1995-12-31'

请记住,Oracle日期数据类型包含时间元素,因此没有时间部分的日期等价于1995-12-31 00:00:00

如果要包括时间部分,则必须使用时间戳文字,其格式为 YYYY-MM-DD HH24:MI:SS[.FF0-9]

select employee_id
  from employee
 where employee_date_hired > timestamp '1995-12-31 12:31:02'

更多信息

NLS_DATE_LANGUAGE源自NLS_LANGUAGENLS_DATE_FORMAT源自NLS_TERRITORY。这些是在最初创建数据库时设置的,但是可以通过更改初始化参数文件(仅在确实需要时)或在会话级别使用ALTER SESSION语法来更改。例如:

alter session set nls_date_format = 'DD.MM.YYYY HH24:MI:SS';

这表示:

  • DD 每月的数字天,1-31
  • MM 年份的数字月份,01-12(一月为01)
  • YYYY4位数字年份-在我看来,这总是比2位数字年份更好,YY因为您所指的世纪没有混淆。
  • HH24 一天中的0到23点
  • MI 每小时的分钟数,0-59
  • SS 分钟,0-59

您可以通过查询找到当前的语言和日期语言设置,V$NLS_PARAMETERSs并通过查询找到有效值的全部范围V$NLS_VALID_VALUES

进一步阅读


顺便说一句,如果您希望将count(*)其分组employee_id

select employee_id, count(*)
  from employee
 where employee_date_hired > date '1995-12-31'
 group by employee_id

这给你计数 employee_id


13
+1,用于在to_date()中使用格式掩码。请注意,由于语言设置不同,在不同的环境下仍然可能失败。DEC不一定总是有效的月份。通常最好使用数字代替名称
a_horse_with_no_name 2012年

1
可以使用ANSI文字指定时间-您只需要指定timestamp文字而不是date文字:(timestamp '2015-01-30 19:42:04' 因为在ANSI SQL中,date数据类型没有时间,只有timestamp数据类型才有时间)。
a_horse_with_no_name 2015年

1
ANSI日期文字确实是一种比较简洁的方法,比较每次必须键入TO_DATE和Date-Format。非常适合像我这样的LAZY开发人员。需要注意的一件事就是DATE 2016-04-01手段2016-04-01 00:00:00。而且我认为此语法自Oracle 9i起就可以使用,因为这是将ANSI-SQL语法引入Oracle的地方。
LeOn-韩立

1
在过去的四年里,我的思想发生了很大的变化@Leon :-)'我已经更新了答案。我曾经提到过,日期文字不包含时间元素,但是正如您所说的,我已经更明确地指出了这一点。9i的扩展支持已于6年前终止,并于14年前发布。它与绝大多数用户不再相关。
2016年


6

结论,

to_char 以自己的方式工作

所以,

始终使用此格式YYYY-MM-DD进行比较,而不要使用MM-DD-YYDD-MM-YYYY或任何其他格式


4

您可以如下使用trunc和to_date:

select TO_CHAR (g.FECHA, 'DD-MM-YYYY HH24:MI:SS') fecha_salida, g.NUMERO_GUIA, g.BOD_ORIGEN, g.TIPO_GUIA, dg.DOC_NUMERO, dg.* 
from ils_det_guia dg, ils_guia g
where dg.NUMERO_GUIA = g.NUMERO_GUIA and dg.TIPO_GUIA = g.TIPO_GUIA and dg.BOD_ORIGEN = g.BOD_ORIGEN
and dg.LAB_CODIGO = 56 
and trunc(g.FECHA) > to_date('01/02/15','DD/MM/YY')
order by g.FECHA;

2

从您的查询:

Select employee_id, count(*) From Employee 
Where to_char(employee_date_hired, 'DD-MON-YY') > '31-DEC-95' 

我认为它不显示1994年6月20日之后的雇员人数。如果要显示雇员人数,可以使用:

Select count(*) From Employee 
Where to_char(employee_date_hired, 'YYYMMMDDD') > 19940620 

我认为,最佳做法是可以比较日期:

employee_date_hired > TO_DATE('20-06-1994', 'DD-MM-YYYY');
or
to_char(employee_date_hired, 'YYYMMMDDD') > 19940620;

-4

由于日期已转换为字符,因此必须在其中添加单引号。

选择employee_id,计数(*)
来自员工
其中to_char(employee_date_hired,'DD-MON-YY')> '31 -DEC-95';

1
该SQL使用隐式日期格式,因此不会始终有效。
乔恩·海勒2014年

5
它仅适用于您的特定NLS_ *设置,可能无法在其他客户端或服务器上使用。可接受的答案说明了为什么显式日期格式很重要。
乔恩·海勒2014年

此方法比较字符串,而不是日期。第二个字符串以“ 3”开头,因此比较的工作方式类似于“字母顺序”。有趣的是,如果您使用YYYY-MM-DD之类的格式,这种类型的比较实际上可以工作(偶然排序)。但是,当然,最好将日期与日期进行比较...
Nick Perkins '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.