错误原因:
听起来您的表格中的日期无效。当正在解析的字符串不正确时,您会收到此错误。这是一个生成它的示例查询。
SELECT TO_DATE('22-10-2016 05:31', 'mm/dd/yyyy hh24:mi') FROM DUAL;
防止这种情况再次发生:
与a_horse_with_no_name implies 一样,使用VARCHAR(或VARCHAR2 或任何文本类型)通常是时间数据的不良数据类型。这是部分原因:很难防止无效数据进入数据库。
首先要防止不良数据进入数据库:
- 理想的解决方案是将这些列转换为实际的时间类型(在修复现有数据之后),例如
TIMESTAMP(可能是WITH TIME ZONE)或DATE。
- 如果这不可行,则添加一个约束或触发器,它会在错误的格式上引发错误。请注意,您需要弄清楚“正确”的格式是什么。这里的部分问题可能是您有非美国用户(或者可能是喜欢 ISO 8601 的精通计算机的人),并且应用程序需要强制执行特定格式或自动解析为您决定的标准
- 如果您真的无法阻止不同的格式进入并且无法转换为实际日期,那么您可以存储一个带有格式的额外列。您仍然需要验证日期是否与同一行中包含的任何格式实际匹配。
- 您还应该查看正在向该数据库添加数据的所有应用程序。它们可能缺乏对输入的验证或包含允许创建无效数据的错误。
修复现有数据:
要找到有问题的行,试试这个。首先创建一个函数:
CREATE OR REPLACE FUNCTION DATETIME_IS_VALID_FOR_FORMAT(
TEXT_DATETIME VARCHAR2,
DATETIME_FORMAT VARCHAR2
)
RETURN VARCHAR2
IS
DUMMYVAR DATE;
BEGIN
-- The assignment is only here to get the function to compile
DUMMYVAR := TO_DATE(TEXT_DATETIME, DATETIME_FORMAT);
RETURN 'TRUE';
EXCEPTION
WHEN OTHERS THEN
RETURN 'FALSE';
END;
/
现在SELECT 这是'FALSE' 所在的行:
SELECT *
FROM timedetail_dates
WHERE
DATETIME_IS_VALID_FOR_FORMAT(timein_date, 'mm/dd/yyyy hh24:mi') != 'TRUE' OR
DATETIME_IS_VALID_FOR_FORMAT(timeout_date, 'mm/dd/yyyy hh24:mi') != 'TRUE'
如果由于数据库权限低而无法创建函数,则必须改用DBMS_OUTPUT。在下面的匿名块中替换ID_COLUMN,您可以使用它来查找坏行:
DECLARE
FUNCTION DATETIME_IS_VALID_FOR_FORMAT(
TEXT_DATETIME VARCHAR2,
DATETIME_FORMAT VARCHAR2
)
RETURN VARCHAR2
IS
DUMMYVAR DATE;
BEGIN
-- The assignment is only here to get the function to compile
DUMMYVAR := TO_DATE(TEXT_DATETIME, DATETIME_FORMAT);
RETURN 'TRUE';
EXCEPTION
WHEN OTHERS THEN
RETURN 'FALSE';
END;
BEGIN
FOR T_ROW IN (SELECT * FROM timedetail_dates) LOOP
IF (
DATETIME_IS_VALID_FOR_FORMAT(T_ROW.TIMEIN_DATE, 'mm/dd/yyyy hh24:mi') != 'TRUE' OR
DATETIME_IS_VALID_FOR_FORMAT(T_ROW.TIMEOUT_DATE, 'mm/dd/yyyy hh24:mi') != 'TRUE'
) THEN
-- Replace ID_COLUMN with your actual primary key
DBMS_OUTPUT.PUT_LINE('Bad row: '||T_ROW.ID_COLUMN);
END IF;
END LOOP;
END;
/
请注意,您可能需要做一些准备才能让您的客户端开始捕获来自DBMS_OUTPUT.PUT_LINE 的输出。 (这取决于客户端,但您必须在 SQL*Plus 和 Oracle SQL Developer 中打开它。)另外请注意,在块完成之前不会显示任何输出。