首页 > 解决方案 > 如何防止 Oracle 中的“坏”日期?

问题描述

我正在为我们的项目开发一个数据库。我们的后端人员能够将“00.00.0000”日期从 Java 插入 Oracle(列数据类型为 DATE)。我想这与本例中的原始值有关:

alter session set nls_date_format='fmdd.month.yyyy hh24:mi:ss';
declare
  d date;
begin
  dbms_stats.convert_raw_value(hextoraw('7764057f7f77aa'), d);
  dbms_output.put_line(d);
end;
/

127.may.1900 126:118:87

我怎样才能防止这种情况?

标签: javasqloracle

解决方案


您可以使用函数通过将日期转换为字符串并返回来检查日期是否有效,并将其添加到CHECK日期列的约束中,以确保所有日期都有效。

但是,您不应该这样做,因为您应该强制在您的系统上不执行任意代码,并且所有应用程序代码都应该包括输入验证,以便只有经过清理的值被插入到数据库中。

一个例子:

甲骨文设置

CREATE TABLE Dates (
  d DATE
);

CREATE FUNCTION isValidDate( dt IN DATE ) RETURN NUMBER
IS
  d DATE;
BEGIN
  d := TO_DATE( TO_CHAR( dt, 'fxYYYY-MM-DD HH24:MI:SS' ), 'fxYYYY-MM-DD HH24:MI:SS' );
  RETURN 1;
EXCEPTION
  WHEN OTHERS THEN
    RETURN 0;
END;

插入日期

declare
  d DATE;

  FUNCTION createUnvalidatedDate(
    centuries INT := 0,
    years     INT := 0,
    months    INT := 0,
    days      INT := 0,
    hours     INT := 0,
    minutes   INT := 0,
    seconds   INT := 0
  ) RETURN DATE
  IS
    dt         DATE;
    hex_string CHAR(14);
  BEGIN
    hex_string := LPAD( TO_CHAR( centuries + 100, 'fmXX' ), 2, '0' )
               || LPAD( TO_CHAR( years + 100,     'fmXX' ), 2, '0' )
               || LPAD( TO_CHAR( months,          'fmXX' ), 2, '0' )
               || LPAD( TO_CHAR( days,            'fmXX' ), 2, '0' )
               || LPAD( TO_CHAR( hours + 1,       'fmXX' ), 2, '0' )
               || LPAD( TO_CHAR( minutes + 1,     'fmXX' ), 2, '0' )
               || LPAD( TO_CHAR( seconds + 1,     'fmXX' ), 2, '0' );
    dbms_stats.convert_raw_value(hextoraw(hex_string), dt);
    RETURN dt;
  END;
begin
  d := createUnvalidatedDate( 19, 0, 5, 127, 126, 118, 87 );
  INSERT INTO Dates ( d ) VALUES ( d );
  d := createUnvalidatedDate( 0, 0, 0, 0, 0, 0, 0 );
  INSERT INTO Dates ( d ) VALUES ( d );
  d := createUnvalidatedDate( 20, 19, 6, 24, 10, 28, 30 );
  INSERT INTO Dates ( d ) VALUES ( d );
end;
/

检查有效性

SELECT d, isValidDate( d ) AS valid
FROM   Dates;

输出:

D | 有效的
:-------------------- | ----:
1900-5-127T126:118:87 | 0
0-0-0T0:0:0 | 0
2019-6-24T10:28:30 | 1

这表明前两个值无效,最后一个是有效日期。

db<>在这里摆弄


推荐阅读