【问题标题】:MySQL - Comparing two dates in the WHERE clauseMySQL - 比较 WHERE 子句中的两个日期
【发布时间】:2021-10-09 04:16:35
【问题描述】:

我有一个表,links,它将两个类别(父母和孩子)联系在一起。该表有五个字段:

  • autoinc
  • parent_category_name year(4) NOT NULL
  • parent_category_year varchar(255) NOT NULL
  • child_category_name year(4) NOT NULL
  • child_category_year varchar(255) NOT NULL

我正在尝试编写一个 INSERT SELECT 来获取父子类别 ID,并将其插入到临时表中。

INSERT INTO temp (parent_category_id, child_category_id)
SELECT parent.parent_category_id, child.child_category_id
  FROM links
  JOIN categories AS parent
       ON   parent.name = link.parent_category_name
       AND  parent.year = link.parent_category_year
  JOIN categories AS child
       ON   child.name = link.child_category_name
       AND  child.year = link.child_category_year

此查询运行良好,但我需要应用一些业务规则。规则是:

  • 父年份必须与子年份相同

  • 父年必须比子年少一年

我在查询中添加了 WHERE 子句:

WHERE link.child_category_year = link.parent_category_year
   OR link.child_category_year - link.parent_category_year = 1 

当这个 INSERT 语句在我的 Perl 代码中执行时,我得到以下异常:

DBI Exception: DBD::mysql::db do failed: BIGINT UNSIGNED value is out of range in '(`my_database`.`links`.`child_category_year` - `my_database`.`links`.`parent_category_year`)' [for Statement "

所以,我认为 INSERT 不喜欢 WHERE 子句中的日期减法。我探索了使用 DATEDIFF 函数,但我不是简单地寻找日期相差一年,而是父母比孩子少一年。

如何在没有插入错误的情况下完成此操作?

【问题讨论】:

标签: mysql sql datediff


【解决方案1】:

OR link.child_category_year - link.parent_category_year = 1 可能会产生负减结果。当然负值不能存储为 UNSIGNED。

只需将您的表达式转换为

OR link.child_category_year = link.parent_category_year + 1 

【讨论】:

    【解决方案2】:

    完全不清楚为什么“年”会被存储为无符号的 bigint。这对我对“年”的理解来说太过分了。

    无论如何,为什么不将逻辑改写为:

    WHERE link.parent_category_year = link.child_category_year
          link.parent_category_year = link.child_category_year + 1 
    

    一般来说,将1 添加到无符号值应该没有问题。

    【讨论】:

      【解决方案3】:

      这是我第一次知道有 YEAR 数据类型,在阅读了 official documentation 之后,我明白了:

      MySQL 以 YYYY 格式显示 YEAR 值,范围为 1901 到 2155,以及 0000。

      虽然没有具体说明类型是UNSIGNED,但文档的最后一行说:

      如果未启用严格 SQL 模式,MySQL 会将无效的 YEAR 值转换为 0000。在严格的 SQL 模式下,尝试插入无效的 YEAR 值会产生错误。

      这意味着您收到错误是因为OR link.child_category_year - link.parent_category_year = 1 条件下的一个(或多个)减去值返回负数。

      现在,您可以尝试以下几个选项:

      1. 您可以使用CAST 函数并将年份数据更改为SIGNED,例如:
      WHERE link.child_category_year = link.parent_category_year
         OR CAST(link.child_category_year AS SIGNED) - CAST(link.parent_category_year AS SIGNED) = 1 
      
      1. 或者您可以设置NO_UNSIGNED_SUBTRACTION sql_mode 并按原样运行查询:
      SET sql_mode='NO_UNSIGNED_SUBTRACTION'
      
      1. 您还可以考虑将YEAR 数据类型更改为INTEGER 并按原样运行查询:
      ALTER TABLE links 
              MODIFY parent_category_year INT NOT NULL,
              MODIFY child_category_year INT NOT NULL;
      

      【讨论】:

        猜你喜欢
        • 2017-09-16
        • 1970-01-01
        • 1970-01-01
        • 2012-01-02
        • 1970-01-01
        • 2017-11-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多