【问题标题】:Setting NULL datetime with Rose::DB::Object and MySQL使用 Rose::DB::Object 和 MySQL 设置 NULL 日期时间
【发布时间】:2010-01-27 03:23:40
【问题描述】:

我在这里可能是错的,但这里似乎有相互冲突的标准。

MySQL 将存储的日期时间“0000-00-00 00:00:00”视为等同于 NULL。 (更新 - 似乎只有在日期时间被定义为 NOT NULL 时)

但是 Rose::DB::Object 对 MySQL DATETIME 字段使用 DateTime,并且尝试从“0000-00-00”设置空 DATETIME 会在 DateTime 模块中引发异常。即,我无法创建具有年 0、月 0、日 0 的 DateTime 对象,因为这会在 DateTime 模块中引发异常。

我检查了 Rose::DB::Object::Metadata::Column::Datetime,但在创建条目或检索时看不到显式处理 NULL DateTime 的方法。

我错过了什么吗?

即,即使 DateTime(Perl 模块)不能,Rose::DB::Object 也可以处理 NULL 日期时间(MySQL)字段。

示例代码:

#!/usr/bin/perl
use strict;
use warnings;
use lib 'lib';
use RoseDB::dt_test;

my $dt_entry =  RoseDB::dt_test->new();
$dt_entry->date_time_field('0000-00-00');
$dt_entry->save;



1;

__END__
# definition of table as stored in DB

mysql> show create table dt_test \G
*************************** 1. row ***************************
       Table: dt_test
Create Table: CREATE TABLE `dt_test` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `date_time_field` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

RoseDB::dt_test 模块是:

package RoseDB::dt_test;
use strict;
use warnings;

# this module builds up our DB connection and initializes the connection through:
# __PACKAGE__->register_db
use RoseDB;

use base qw(Rose::DB::Object);

__PACKAGE__->meta->setup (
    table => 'dt_test',

    columns =>
    [
      id              => { type => 'int', primary_key => 1 },
      date_time_field => { type => 'datetime' },
    ],
);

sub init_db { RoseDB->get_dbh }

1;

当我运行它时,我收到错误“Invalid datetime: '0000-00-00' at tmp.pl line 8”

当我将日期更改为“2010-01-01”时,它按预期工作:

mysql> select * from dt_test\G
*************************** 1. row ***************************
             id: 1
date_time_field: 2010-01-01 00:00:00

我终于设法重新创建了 NULL MySQL 查询示例!

mysql> create table dt_test(dt_test_field datetime not null);
Query OK, 0 rows affected (0.05 sec)

mysql> insert into dt_test values(null);
ERROR 1048 (23000): Column 'dt_test_field' cannot be null
mysql> insert into dt_test values('0000-00-00');
Query OK, 1 row affected (0.00 sec)

mysql> select * from dt_test;
+---------------------+
| dt_test_field       |
+---------------------+
| 0000-00-00 00:00:00 |
+---------------------+
1 row in set (0.00 sec)

mysql> select * from dt_test where dt_test_field is null;
+---------------------+
| dt_test_field       |
+---------------------+
| 0000-00-00 00:00:00 |
+---------------------+
1 row in set (0.00 sec)

看起来像用“NOT NULL”定义日期时间的表定义,然后尝试使用 MySQL“fake null”是问题所在。我现在玩这个太累了,但我会在早上更改表结构时看看会发生什么。

【问题讨论】:

  • 一些示例代码会有所帮助。数据库的前后状态是什么,您使用什么 Perl 代码来尝试进行更改?
  • 所以,总而言之,这里有两个问题 - (1) MySQL 很奇怪,当它被定义为 NOT NULL 时,它的 datetime 字段设置为 '0000-00-00'。 (2) 我仍然无法通过 Rose::DB::Object 将日期时间字段设置为 NULL

标签: mysql perl rose-db-object


【解决方案1】:

您应该能够将 datetime 列设置为所需的文字 0000-00-00 00:00:00 值并将其保存到数据库中:

$o->mycolumn('0000-00-00 00:00:00');
$o->save;

Rose::DB::Object 不会将此类“全零”值转换为 DateTime 对象,而是保留为文字字符串。没有与 MySQL 的 0000-00-00 00:00:00 日期时间字符串等效的语义 DateTime 对象。

注意:0000-00-00 是有效的date 值,但datetime(或timestamp)值必须包含时间:0000-00-00 00:00:00

要将列设置为空,请将undef 作为列值传递:

$o->mycolumn(undef);

当然,如果数据库中的列定义包含NOT NULL 约束,save() 将不起作用。

【讨论】:

  • 似乎不起作用。我收到错误:/Library/Perl/5.8.8/Rose/Object.pm 第 25 行(版本 0.855)的日期时间无效:'0000-00-00'
  • 另外,我发现我无法将字段留空然后保存,因为我一直收到“name_of_timestamp 字段不能为空”错误,即使它可以。如果这是有道理的:)
【解决方案2】:

MySQL 允许日期类型不完整(缺少年、月或日)。 '0000-00-00' 是有效的、非 NULL MySQL 日期。为什么你认为它匹配 IS NULL?

$ echo "select date('0000-00-00') is null" | mysql
date('0000-00-00') is null
0

比较:

$ echo "select date('0000-00-32') is null" | mysql
date('0000-00-32') is null
1

【讨论】:

  • 我认为您误解了 - “SELECT dial_timestamp FROM table WHERE dial_timestamp IS NULL”匹配 dial_timestamp(日期时间)字段为“0000-00-00 00:00:00”的值。我想要做的是使用 Rose::DB::Object 在某些 DB 表中获取和设置空日期 - 按照惯例,这是 MySQL 中的“0000-00-00 00:00:00”
  • 你错了——至少在我用过的任何版本的 MySQL 上都没有。试试看:create table foo (bar datetime) select '0000-00-00 00:00:00' bar; select * from foo where bar is null; select * from foo where bar = '0000-00-00 00:00:00'; select *, bar is null, bar = '0000-00-00 00:00:00' from foo;
  • 奇怪,我确信这就是之前发生的事情,但现在我无法重现。嗯。我想我需要睡在那个上面。谢谢。
  • 设法重现(见上文) - 看起来像 MySQL 的怪异。哦,快乐。
  • 可爱。我也发生在 5.0.32 和 5.0.75 :(
猜你喜欢
  • 2011-07-06
  • 1970-01-01
  • 1970-01-01
  • 2014-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-27
相关资源
最近更新 更多