【问题标题】:Blocking '0000-00-00' from MySQL Date Fields从 MySQL 日期字段中阻止“0000-00-00”
【发布时间】:2011-04-22 22:57:57
【问题描述】:

我有一个数据库,其中旧代码喜欢在 Date 和 DateTime 列中插入“0000-00-00”而不是实际日期。所以我有以下两个问题:

  1. 我可以在数据库级别上做些什么来阻止它吗?我知道我可以将一列设置为非空,但这似乎并没有阻止这些零值。
  2. 检测日期字段中现有零值的最佳方法是什么?我有大约一百个表,每个表有 2-3 个日期列,我不想单独查询它们。

跟进:

默认值已设置为 null。很久以前,默认值为“0000-00-00”。一些代码仍然明确放置“0000-00-00”。我宁愿强制该代码抛出错误,以便隔离并删除它。

【问题讨论】:

  • 我不敢相信 MySQL 不支持 CHECK 约束。我打算将其发布为答案,这不是一个选择。越来越多的,我理解 MySQL 的恨。自己从来没用过。

标签: mysql datetime date data-cleaning


【解决方案1】:

我可以在数据库级别做些什么来阻止这个吗?

是的,启用 NO_ZERO_DATE 模式:

SET sql_mode = 'NO_ZERO_DATE';

The behaviour is documented。此外,您可能还希望将模式设置为包括 NO_ZERO_IN_DATE...

还要确保 sql_mode 包含 STRICT_ALL_TABLES 或 STRICT_TRANS_TABLES;没有这些 NO_ZERO_IN_DATE 只会发出警告,但插入仍然成功。

检测日期字段中现有零值的最佳方法是什么?我有大约一百个表,每个表有 2-3 个日期列,我不想单独查询它们。

单独的列意味着必须单独检查它们——对此您无能为力。

【讨论】:

  • (这仅在插入新数据时有效 - 如果您有一个充满不良数据的数据库,则帮助不大)
【解决方案2】:

假设您无法轻松修复数据和“SET sql_mode = 'NO_ZERO_DATE';”,您可以在表上创建一个视图...

CREATE VIEW filter AS
SELECT other_column, 
CASE 
  WHEN realtable.dodgy_date = 0 THEN NULL 
  ELSE realtable.dodgy_date
END AS dodgy_date
FROM realtable;

【讨论】:

    【解决方案3】:

    如果输入的日期无关紧要(即,只要它不为零),您可以更改列定义以使用 NOW() 作为默认值。可能不是一个理想的解决方案,但它确实满足标准: 1) 非空 2) 非零 其实我真的不为这个建议感到骄傲

    【讨论】:

      【解决方案4】:

      您可以使列可以为空,并将 NULL 作为默认值,但听起来您已经拥有它并且它不起作用。虽然...它可能是您用来显示数据的工具不喜欢显示NULL 日期...您使用的是什么工具?还是代码检索的数据中出现了“0000-00-00”?

      您可以设置一个非 null 且易于识别为默认值的默认值,例如 1900-01-01(假设您通常不处理接近此日期的日期)。

      【讨论】:

        【解决方案5】:

        trigger 可用于强制列的值。

        【讨论】:

          【解决方案6】:

          默认设置时间戳可能是您的一个选项,为此使用表更改语句:

          ALTER TABLE mytable CHANGE date_update timestamp NOT NULL DEFAULT CURRENT_DATE()
          

          MySQL CURRENT_DATE() documentation at w3c resource

          删除零日期并将其替换为例如当前日期:

          UPDATE mytable SET date_update = CURRENT_DATE() where date_update = "0000-00-00"
          

          【讨论】:

            【解决方案7】:

            这是我使用的触发器:

            delimiter //
            CREATE TRIGGER bad_date BEFORE INSERT ON some_table
                FOR EACH ROW
                    BEGIN
                        IF NEW.the_date='0000-00-00' THEN 
                            SET NEW.the_date= CURDATE();
                        END IF;
                    END;//
            

            如果更新是一个问题,添加一个单独的触发器(更新前)来做同样的事情。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2013-06-09
              • 2017-09-21
              • 2013-07-12
              • 1970-01-01
              • 2015-07-19
              • 1970-01-01
              • 2013-01-11
              相关资源
              最近更新 更多