【问题标题】:Why won't this simple SQL statement work?为什么这个简单的 SQL 语句不起作用?
【发布时间】:2009-12-24 21:49:37
【问题描述】:

dateposted 是 MySQL TIMESTAMP 列:

 SELECT * 
   FROM posts 
  WHERE dateposted > NOW() - 604800

...应该,如果我没记错的话,返回上周dateposted 所在的行。但它只返回不到大约 1 天的帖子。我的印象是TIMESTAMP 用了秒?

IE:7 * 3600 * 24 = 604800

【问题讨论】:

    标签: sql mysql database datetime timestamp


    【解决方案1】:

    用途:

    WHERE dateposted BETWEEN DATE_ADD(NOW(), INTERVAL -7 DAY) AND NOW()
    

    【讨论】:

    • +1 我希望这个解决方案比我给出的答案更能从索引中受益。
    • 绝对!谢谢你。我不知道我是如何让这样的 SQL 在我的上一个网站上工作的。
    【解决方案2】:

    那是因为now()是从时间戳隐式转换成数字,mysql转换规则会创建一个像YYYYMMDDHHMMSS.uuuuuu这样的数字

    来自 mysql 文档:

    mysql> SELECT NOW();
            -> '2007-12-15 23:50:26'
    mysql> SELECT NOW() + 0;
            -> 20071215235026.000000
    

    【讨论】:

    • 终于说得通了。我的印象是它更改为 UNIX_TIMESTAMP。谢谢。
    • 呃,它真的改变了你对数据的解释吗?
    【解决方案3】:

    也许在内部。做到这一点的方法是日期数学函数。所以它会是:

    SELECT * FROM posts WHERE dateposted > DATE_ADD(NOW(), INTERVAL -7 DAY)
    

    我认为有一个DATE_SUB,我只是习惯了到处使用ADD。

    【讨论】:

      【解决方案4】:

      不,您不能对TIMESTAMPDATETIME 和其他与日期相关的数据类型隐式使用整数运算。您正在考虑 UNIX 时间戳格式,它是自 1970 年 1 月 1 日以来的整数秒数。

      您可以在 MySQL 中将 SQL 数据类型转换为 UNIX timestamp,然后使用算术:

      SELECT * FROM posts WHERE UNIX_TIMESTAMP(dateposted)+604800 > NOW()+0;
      

      注意:将零添加到 NOW() 使其返回数值而不是字符串值。


      更新:好的,我对上面的查询完全错误。将NOW() 转换为数字输出不会产生可以与 UNIX 时间戳进行比较的数字。它产生一个数字,但该数字不计算秒数或其他任何东西。这些数字只是 YYYYMMDDHHMMSS 串在一起。

      例子:

      CREATE TABLE foo (
        id SERIAL PRIMARY KEY,
        dateposted TIMESTAMP
      );
      
      INSERT INTO foo (dateposted) VALUES ('2009-12-4'), ('2009-12-11'), ('2009-12-18');
      
      SELECT * FROM foo;
      
      +----+---------------------+
      | id | dateposted          |
      +----+---------------------+
      |  1 | 2009-12-04 00:00:00 |
      |  2 | 2009-12-11 00:00:00 |
      |  3 | 2009-12-18 00:00:00 |
      +----+---------------------+
      
      SELECT *, UNIX_TIMESTAMP(dateposted) AS ut, NOW()-604800 AS wk FROM foo
      
      +----+---------------------+------------+-----------------------+
      | id | dateposted          | ut         | wk                    |
      +----+---------------------+------------+-----------------------+
      |  1 | 2009-12-04 00:00:00 | 1259913600 | 20091223539359.000000 |
      |  2 | 2009-12-11 00:00:00 | 1260518400 | 20091223539359.000000 |
      |  3 | 2009-12-18 00:00:00 | 1261123200 | 20091223539359.000000 |
      +----+---------------------+------------+-----------------------+
      

      很明显,数值是不可比较的。但是,UNIX_TIMSTAMP() 也可以转换该格式的数值,因为它可以转换时间戳的字符串表示形式:

      SELECT *, UNIX_TIMESTAMP(dateposted) AS ut, UNIX_TIMESTAMP(NOW())-604800 AS wk FROM foo
      
      +----+---------------------+------------+------------+
      | id | dateposted          | ut         | wk         |
      +----+---------------------+------------+------------+
      |  1 | 2009-12-04 00:00:00 | 1259913600 | 1261089774 |
      |  2 | 2009-12-11 00:00:00 | 1260518400 | 1261089774 |
      |  3 | 2009-12-18 00:00:00 | 1261123200 | 1261089774 |
      +----+---------------------+------------+------------+
      

      现在可以使用比较它们的表达式运行查询:

      SELECT * FROM foo WHERE UNIX_TIMESTAMP(dateposted) > UNIX_TIMESTAMP(NOW())-604800
      
      +----+---------------------+
      | id | dateposted          |
      +----+---------------------+
      |  3 | 2009-12-18 00:00:00 |
      +----+---------------------+
      

      但是@OMGPonies 给出的答案仍然更好,因为我的查询中的这个表达式可能无法使用索引。我只是提供这个来解释TIMESTAMPNOW() 功能的工作原理。

      【讨论】:

      • 有什么理由比简单地使用日期数学函数更受欢迎吗?
      • 不,我赞成@OMGPonies 的答案,我更喜欢这种用法。我显示上面的表达式只是因为它更类似于 OP 的查询。
      • 那为什么它仍然显示结果而不是错误?我很困惑。好吧,我在发布之前尝试的第一件事是执行 UNIX_TIMESTAMP(dateposted)> NOW() - 604800,但是(和你一样)返回一个空集。
      • @Douglas:我想如果您使用原始查询格式,那么您应该减去 7000000(七百万),因为这是隐式时间戳转换的方式(请参阅我的答案)
      【解决方案5】:

      试试这个查询:

      SELECT * FROM posts WHERE DATE_SUB(CURDATE(),INTERVAL 7 DAY) < dateposted;
      

      我假设您使用的是 mySQL。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多