0

我有一个问题

SELECT DISTINCT ID 
  From ACCUSED 
 WHERE CAST(DATE_ENTERED AS date) BETWEEN '12-Apr-2013' and '12-Apr-2013'

此查询显示错误“不是有效月份”

如果我在字符串日期不为空的其他表上应用相同的查询,则它可以正常工作。这工作很好

SELECT DISTINCT ID 
  From Customer 
 WHERE CAST(DATE_ENTERED AS date) BETWEEN '12-Apr-2013' and '12-Apr-2013'
4

1 回答 1

3

假设这DATE_ENTERED是一VARCHAR2

  1. 您永远不应该将日期存储为字符串。日期应存储在DATE列中。使用错误的数据类型是问题的根源,修复数据模型以使用正确的数据类型是正确的解决方案。
  2. 如果要将字符串转换为日期,请TO_DATE使用具有显式格式掩码的函数。没有格式掩码的ACAST或 aTO_DATE将导致会话NLS_DATE_FORMAT指定为格式掩码的任何内容。由于每个会话可能不同,这意味着您的代码可能适用于某些客户端的某些用户,而不适用于其他用户或其他客户端,并且不可避免地难以找到错误。
  3. 应始终将ADATE与另一个进行比较,而DATE不是与字符串进行比较。将日期与字符串进行比较会迫使 Oracle 进行隐式转换,该转换再次使用会话NLS_DATE_FORMAT,并再次使您的代码不可靠。如果要指定文字日期,请使用该TO_DATE函数将字符串转换为日期(带有显式格式掩码)或使用 ANSI 日期文字
  4. 假设这ID是主键,那么DISTINCT充其量是没有意义的,最坏的情况是迫使 Oracle 进行不必要的排序。

第一个最佳解决方案是修改数据模型DATE_ENTERED,实际上是一个DATE. 如果您这样做,您的查询将变为(使用 ANSI 日期文字)

SELECT id
  FROM accused
 WHERE date_entered BETWEEN date '2013-04-12' and date '2013-04-12'

或显式TO_DATE

SELECT id
  FROM accused
 WHERE date_entered BETWEEN to_date( '12-Apr-2013', 'DD-Mon-YYYY' ) 
                        AND to_date( '12-Apr-2013', 'DD-Mon-YYYY' ) 

如果由于某种原因,您遇到了不正确的数据模型,如果您存储的所有字符串实际上都是有效的,您可以执行类似的操作

SELECT id
  FROM accused
 WHERE to_date( date_entered, 'DD-Mon-YYYY' ) BETWEEN to_date( '12-Apr-2013', 'DD-Mon-YYYY' ) 
                                                  AND to_date( '12-Apr-2013', 'DD-Mon-YYYY' ) 

但是,鉴于您遇到的错误,似乎很有可能在表中至少有一些行,其中存储在表中的字符串不代表有效日期。然后问题就变成了试图找出哪些行是无效的。一种选择是创建一个新功能

CREATE OR REPLACE FUNCTION my_to_date( p_date_str    IN VARCHAR2,
                                       p_format_mask IN VARCHAR2 )
  RETURN DATE
IS
  l_date DATE;
BEGIN
  l_date := to_date( p_date_str, p_format_mask );
  RETURN l_date;
EXCEPTION
  WHEN others THEN
    RETURN NULL;
END;

然后在您的查询中使用该函数。

SELECT *
  FROM accused
 WHERE date_entered IS NOT NULL
   AND my_to_date( date_entered, 'DD-Mon-YYYY' ) IS NULL

DATE_ENTERED将返回格式中不代表有效日期的所有行DD-Mon-YYYY。您最终必须更正这些数据。如果您可以忽略任何包含无效数据的行,则可以编写查询

SELECT id
  FROM accused
 WHERE my_to_date( date_entered, 'DD-Mon-YYYY' ) BETWEEN to_date( '12-Apr-2013', 'DD-Mon-YYYY' ) 
                                                     AND to_date( '12-Apr-2013', 'DD-Mon-YYYY' ) 
于 2013-04-12T08:01:03.693 回答