2

您好我正在尝试通过 Servlet 在 SQL 数据库中插入日期。如果帖子提交的字段生日是空的,那么它应该插入 0000-00-00

但这有点复杂。

我这样做是有效的:

if (birthdate == null) {
            ps_employee.setInt(4, 0); //ps_employee is my PreparedStatement
        } else {
            ps_employee.setDate(4, birthdate);
        }

如果 post 字段没有值,则生日为 null。否则生日包含一个有效的 java.sql.date 对象。

上面的代码有效,但它在 sql 中显示警告:“生日数据被截断”....

有没有更好的方法来插入 0000-00-00 日期???

感谢您的帮助..

4

7 回答 7

3
  String query="INSERT INTO tablename values(?) "
  Connection connection = get the dbconn;
  PreparedStatement preparedStatement= connection.prepareStatement(query);      
  preparedStatement.setNull(0, java.sql.Types.DATE)
于 2012-09-25T21:25:15.073 回答
2

该解决方案取决于系统的数据完整性要求。

有两种(也只有两种)选择:

  1. 系统的设计(有设计,对吗?)要求每条记录都有一个有效的出生日期。在这种情况下,UI 有责任强制执行此操作。您的代码将永远不会收到空日期,如果收到,则有理由抛出异常。这消除了你的问题。
  2. 在某些情况下,缺少出生日期是可以接受的。在这种情况下,必须更改表定义以允许空值。

您要做的最后一件事是编造一些特殊的日期值作为 NULL 的替身。该列不是 NULL 的事实表明上述情况 (1) 适用,并且您的特殊日期实际上违反了系统的数据完整性不变量。每个未来负责维护代码的程序员都会诅咒你的名字。

于 2012-09-25T21:50:09.633 回答
2

如果提交的字段为空,您应该存储null,而不是在接下来的 20 年中每个使用该数据的应用程序都必须检查的魔法值。

在输出时转换null为 '0000-00-00' - 或其他任何内容。

于 2012-09-25T21:25:38.817 回答
1

没有好的解决方案

如何处理数据库中的空日期时间值的问题没有好的解决方案。

避免 NULL

正如Chris Date 博士在 SQL 标准指南和其他地方所解释的那样, NULL是一场血腥的噩梦。一般来说,如果可能的话,应该避免它们。在 SQL 数据库中,这意味着将每一列声明为NOT NULL(我希望有一种方法可以将其设为默认值)。在合理的情况下,我们设置了某种默认值。

日期时间没有好的默认值

但是为日期时间值设置默认值可能会非常混乱。SQL 标准和 JDBC/java.sql.* 都没有将任何特定值定义为“空”标志。

Java 8 及更高版本中内置的java.time框架确实将最小值和最大值定义为InstantLocalDateTimeLocalDateLocalTime类中的常量。除了解决的关键问题外,这些值可能用作标志值。这些 java.time 类解析为纳秒,而许多数据库具有更大的粒度,例如Postgres中的微秒。最小值和最大值非常极端,以至于当截断到更小的粒度时它们的含义会发生变化。

零值

您可能会直观地考虑考虑零值日期时间,0000-00-00 00:00:00.0// 0000-00-0000:00:00.0没那么简单。

没有零月/日

首先,没有 的月份00,也没有 的日期00。所以,好吧,我们可以把它改成0000-01-01,一月一日。

没有零年

下一期:没有0000. 我不知道所有数据库,但至少在 Postgres 中没有这样的零年。尝试插入这样的值会产生错误。

INSERT INTO moment_  -- TIMESTAMP WITH TIME ZONE.
VALUES (  '0000-01-01 00:00:00.0Z' ) ;

…抛出错误:

ERROR:  date/time field value out of range: "0000-01-01 00:00:00.0Z"
LINE 2: VALUES (  '0000-01-01 00:00:00.0Z' ) ;
                  ^
********** Error **********

更改0000为第一年的0001作品。

INSERT INTO moment_  -- TIMESTAMP WITH TIME ZONE.
VALUES (  '0001-01-01 00:00:00.0Z' ) ;

SET TIME ZONE 'UTC' ;

TABLE moment_ ;

0001-01-01 00:00:00+00

BC这个数字是对比AD时代的支点。让我们减去一个小时来看看从 AD 移动到 BC 的行为。顺便说一下,诸如BC依赖于语言环境的字符串可能会因您而异。另外,请注意,我们必须将时区设置为UTC才能正确完成此日期时间操作。

SET TIME ZONE 'UTC' ;

INSERT INTO moment_  -- TIMESTAMP WITH TIME ZONE.
VALUES ( TIMESTAMP '0001-01-01 00:00:00.0Z' - INTERVAL '1 hour' ) ;

SET TIME ZONE 'UTC' ;

TABLE moment_ ;

结果是年份,所以我们从to0001 BC跳转;没有零年。00010001 BC0000

“0001-12-31 23:00:00+00 BC”

因此,如果您决定使用某个标志值,则不能使用真正的零值,但可以使用接近零的值,即公元第一年一月的第一天:'0001-01-01 00:00:00.0Z'

时区

使用此特殊标志值时,您必须注意时区。

传递字符串时,会隐式应用 SQL 会话的当前默认时区(至少在 Postgres 中)。

对 NULL 进行排序

在我自己的工作中,我确实将几乎所有列都设为 NOT NULL 并设置了默认值。但是日期时间列是一个例外,因为没有可用的标志值。我已经为此受苦了。具体来说,我学习了如何使用NULLS FIRST/NULLS LAST修饰符的艰难方法,因为SQL 标准没有明确定义 NULL 的默认排序顺序

于 2016-02-03T02:33:31.563 回答
0

我会这样做的方式是通过列的默认值。根据类型将默认设置为“0000-00-00”或“0000-00-00 00:00:00”。

一旦您在数据库中设置了默认值,那么您就不会在插入语句中提供该字段。您可以对不允许为空的列执行此操作,它仍将插入 MySQL 伪空日期。

如果这样做,那么您还应该将此参数添加到您的 SQL 连接字符串中,因为您无法读取 zeroDate...

zeroDateTimeBehavior=convertToNull

最终结果是您将这些日期处理为 Java 中的 null 和 MySQL 数据库中的 0000-00-00。

于 2013-10-09T23:42:06.510 回答
0

您收到错误的原因是您尝试插入无效日期。没有 0 月和 0 日之类的东西。MySQL 不会接受它作为日期。

要么使用其他用户描述的 NULL,要么使用您定义的一些最小基线日期,例如“1100-01-01”

于 2012-09-25T21:27:13.980 回答
0

如果您的数据允许 NULL,但您的 SQL 表不允许(例如复合键的日期部分),您可以使用普遍接受的“空”值(GUI 工具使用此值)来表示默认/空白日期。这是和示例:

private static final String EMPTY_MYSQL_DATE = "0000-00-00 00:00:00";    
...
if(someDateObj == null) {
    preparedStatement.setString(++psIndex, EMPTY_MYSQL_DATE);
} else {
    preparedStatement.setTimestamp(++psIndex, new Timestamp(someDateObj.getTime()));
}
于 2016-02-01T18:38:46.853 回答