【问题标题】:sqlalchemy date as string in raw sqlsqlalchemy 日期作为原始 sql 中的字符串
【发布时间】:2013-03-23 08:43:10
【问题描述】:

考虑下表:

class Employee(Base):
    __tablename__ = "t_employee"

    id = Column(Integer(20), Sequence('%s_id_seq' % __tablename__), primary_key=True)
    first_name = Column(String(30))
    last_name = Column(String(30))
    email = Column(String(50))
    start_date = Column(Date, default=datetime.now)
    end_date = Column(Date)

如何在 sqlalchemy 的原始 sql 中选择使用字符串而不是日期?以下在 mysql 中有效,但在 Oracle 中无效:

session.query(Employee).\
    filter("end_date IS NULL OR end_date>='%s'" % datetime.now()).all()

最好的情况是在处理 Date 或 DateTime 列时我可以使用字符串或日期(可互换)(我尝试过 TypeDecorator 无济于事)

请注意,问题是指 raw sql(我知道这可以使用谓词来完成)...

【问题讨论】:

    标签: python date sqlalchemy


    【解决方案1】:

    不要使用字符串格式将值插入 SQL。在datetime 对象的情况下,默认的字符串格式恰好适用于 MySQL,但这只是偶然和运气。

    在这种情况下,不要使用原始 SQL 并让 SQLAlchemy 将 datetime 对象转换为后端数据库为您理解的内容:

    from sqlalchemy import or_
    
    session.query(Employee).filter(
        or_(Employee.end_date == None, Employee.end_date >= datetime.now())
    ).all()
    

    即使使用原始 SQL,我也会让 sqlalchemy 生成该 SQL 并使用绑定参数:

    from sqlalchemy.sql.expression import bindparam, column
    from sqlalchemy.types import DateTime
    from sqlalchemy import or_
    
    dtnow = bindparam('dtnow', datetime.now(), DateTime)
    end_date = column('enddate', DateTime)
    
    session.query(Employee).\
        filter(or_(end_date == None, end_date >= dtnow)).all()
    

    该过滤器表达式会为您的数据库后端转换为正确转义的 SQL,无论后端可能是什么。当没有设置后端时,表达式变为:

    >>> str(or_(end_date == None, end_date >= dtnow))
    'enddate IS NULL OR enddate >= :dtnow'
    

    并且datetime.now()值会在执行时作为SQL参数传入后端数据库游标。

    最后的手段是使用text() type:

    from sqlalchemy.sql.expression import bindparam, text
    
    dtnow = bindparam('dtnow', datetime.now(), DateTime)
    session.query(Employee).\
        filter(text('end_date is NULL or end_date >= :dtnow', bindparams=[dtnow])).all()
    

    否则我会避免完全混合原始 SQL 和 SQLAlchemy ORM。仅对数据库连接直接使用原始 SQL:

    conn = session.connection()
    conn.execute(text('SELECT * FROM t_employee WHERE end_date IS NULL OR end_date>=:dtnow'),
       dtnow=datetime.now())
    

    【讨论】:

    • 正如我所说,我知道这可以使用谓词来完成,我也知道这是最好的方法,但我的问题是关于原始 SQL
    • @Ofir:那么不要混合使用原始 SQL 和声明性语句。如果需要使用原始 SQL,请使用连接 .execute() 方法,并改用 SQL 参数。
    • 你能举个例子吗? 10 倍。
    • 谢谢马丁。值得注意的是,还有一个有用的text 函数可以做到这一点。
    猜你喜欢
    • 2017-11-30
    • 2021-03-27
    • 1970-01-01
    • 1970-01-01
    • 2016-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多