【问题标题】:SqlAlchemy mysql millisecond or microsecond precisionSqlAlchemy mysql 毫秒或微秒精度
【发布时间】:2015-06-25 00:10:28
【问题描述】:

我一直在冒险尝试让分数时间分辨率在我的数据库中正常工作。我使用 python 方法datetime.now() 来创建日期对象。然后我将这些对象存储在一个字段中,该字段映射到来自 SqlAlchemy 库的COLUMN(DATETIME(9))。最初,我收到一个错误,即我的数据被截断。这是因为我使用的是 mysql 5.5。我已经更新到 5.6.19 并且不再收到数据截断错误。

但是,数据库实际上仍然不包含分数时间条目。例如,下面是实例化 datetime.now() 对象时的值:

2015-04-17 16:31:12.804444

以上正是我所期望的。内存中的对象具有微秒分辨率。现在,将其保存到 mysql 数据库后,如果我打开 mysql 命令行客户端并使用 select 语句返回该行,我会看到以下值:

2015-04-17 16:31:13

显然,该值被四舍五入到最接近的秒数。这很糟糕,我不知道是什么原因造成的!

如果相关,我使用的是 mysql-connector-python==2.0.3

更新: 我也尝试使用COLUMN(DATETIME(6)),但得到了相同的行为。

如果信息相关,我会在下面包括模型:

class User(Base):
        __tablename__ = 'Users'

        uid = Column(INT, primary_key=True, autoincrement=True)
        dateCreated = Column(DATETIME(6))

        def __init__(self, *args, **kwargs):
                super(user, self).__init__(*args, **kwargs)
                self.dateCreated = datetime.now()

更新: Pedro 的建议不是问题,尽管它确实帮助我取得了进步,非常感谢。我尝试单步执行 sql 连接器中的代码,直到找到 mysql insert 语句。该语句确实包含小数时间值。但是,在执行时,该值是四舍五入的。当我在桌子上进行描述时,我注意到日期时间类型就是datetime,而实际上它应该是datetime(6)

我使用 SA 模型生成数据库本身,该模型明确声明 Column(DATETIME(6))Base.metadata.create_all(self.db, checkfirst=True) ,所以我不明白为什么 (6) 没有最终出现在实际的表结构中。不过我想我很快就会弄明白的,我会在我这样做的时候发布更新。

更新: DATETIME 的构造函数不接受字段长度规范。它只需要时区的参数。我不清楚如何指定日期时间字段的长度,因为对于像 varchar 这样的类型,只需将其传递给构造函数。潜水继续。

【问题讨论】:

  • 当您将值选择回 Python 时,您“最终得到了这个”?使用mysql 命令行工具或一些GUI 工具查看它们?
  • 另外,根据the docs,“fsp 值,如果给定,必须在 0 到 6 的范围内。值为 0 表示没有小数部分。如果省略,则默认精度为 0。”那么,您确定DATETIME(9) 没有将 9 视为“不在 0 到 6 范围内,忽略并使用默认值(即 0)”吗?
  • 另外,您可以使用其他工具插入以微秒为单位的值吗?这将有助于排除问题出在 mysql-connector-python 的哪一侧……

标签: python mysql datetime sqlalchemy milliseconds


【解决方案1】:

为了在 MySQL 中强制使用小数秒精度,同时在其他引擎上保持默认值,您可以修改 SQLAlchemy 为 MySQL 编译 DateTime 类型的方式。

from sqlalchemy.ext.compiler import compiles
from sqlalchemy.types import DateTime
from sqlalchemy.dialects.mysql import DATETIME

@compiles(DateTime, "mysql")
def compile_datetime_mysql(type_, compiler, **kw):
     return "DATETIME(6)"

它基本上是告诉 sql alchemy 使用仅为 mysql 的自定义类型编译 DateTime,在我们的例子中返回 DATETIME(6) 其中值为 6 的参数是 fsp(小数秒精度 [来自 MySQL 5.6.4] )

【讨论】:

    【解决方案2】:

    我遇到的问题是库存 SqlAlchemy DATETIME 类不能满足 mysql 将 (6) 值传递给构造函数以表示小数时间值的要求。相反,需要使用sqlalchemy.dialects.mysql.DATETIME 类。此类允许使用fsp 参数(小数秒参数)。因此,列声明实际上应该如下所示:

    dateCreated = Column(DATETIME(fsp=6)) 
    

    感谢其他回复的人。它帮助指导我的调查最终发现了这个深奥且非常令人困惑的区别。

    【讨论】:

    【解决方案3】:

    这似乎是 MySQLdb 的未解决问题,而不是 MySQL 或 SQLAlchemy。

    http://sourceforge.net/p/mysql-python/feature-requests/24/

    您可以尝试使用另一个 MySQL 驱动程序库 -- 检查 SQLAlchemy documentation 以获得支持的选项 -- 或者您可以尝试打开问题中建议的 monkeypatch。

    【讨论】:

    • 有没有办法知道哪个mysql驱动支持这个功能?
    【解决方案4】:

    根据MySQL documentation,它只支持最高6位(微秒)的精度:

    “MySQL 5.6.4 及更高版本扩展了对 TIME、DATETIME 和 TIMESTAMP 值的小数秒支持,精度高达微秒(6 位)”

    我不确定,但指定 9 位数字可能会将列恢复为较小的默认精度。

    【讨论】:

      猜你喜欢
      • 2011-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-07
      • 2015-07-20
      • 2013-03-09
      • 1970-01-01
      相关资源
      最近更新 更多