我有一个查询
SELECT DISTINCT ID
From ACCUSED
WHERE CAST(DATE_ENTERED AS date) BETWEEN '12-Apr-2013' and '12-Apr-2013'
此查询显示错误“非有效月份”
如果我在我的另一个表上应用相同的查询,其中字符串日期不为null,它可以正常工作。 这很好用
SELECT DISTINCT ID
From Customer
WHERE CAST(DATE_ENTERED AS date) BETWEEN '12-Apr-2013' and '12-Apr-2013'
答案 0 :(得分:2)
假设DATE_ENTERED
是VARCHAR2
列
DATE
列中。使用错误的数据类型是问题的根源,修复数据模型以使用正确的数据类型是正确的解决方案。TO_DATE
函数。没有格式掩码的CAST
或TO_DATE
将导致会话的NLS_DATE_FORMAT
指定为格式掩码。由于每个会话可能会有所不同,这意味着您的代码可能适用于某些客户的某些用户而不适用于其他用户或其他客户端,并且这些错误将不可避免地难以找到。DATE
与另一个DATE
进行比较而不是字符串。将日期与字符串进行比较会强制Oracle进行隐式转换,再次使用会话的NLS_DATE_FORMAT
并再次使您的代码不可靠。如果要指定文字日期,请使用TO_DATE
函数将字符串转换为日期(使用显式格式掩码)或使用ANSI日期文字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' )