【问题标题】:SQLAlchemy: How to cast string value to date in multiple insert statement?SQLAlchemy:如何在多个插入语句中将字符串值转换为日期?
【发布时间】:2016-09-09 06:04:35
【问题描述】:

我有一个 dict 对象列表

data = [
{'id': 1, 'dt':'2002-01-02' },
{'id': 2, 'dt':'2014-01-15' },
{'id': 3, 'dt':'2005-10-20' }
]

以及使用 sqlalchemy 创建的 sqlite 中的表,如下所示

engine = create_engine(config.SQLALCHEMY_DATABASE_URI)
metadata = MetaData()

tbl1 = Table('t1', metadata,
                     Column('the_id', Integer, primary_key=True),
                     Column('the_dt', Date))

metadata.create_all(bind=engine)

stmt_insert = tbl1.insert().values(the_id=bindparam('id'), the_dt=bindparam('dt', type_=Date)

with engine.connect() as conn:
    conn.execute(stmt_insert, data)

这给了我以下错误:

sqlalchemy.exc.StatementError: (builtins.TypeError) SQLite 日期类型 只接受 Python 日期对象作为输入。

我应该为“type_”参数分配什么来使这个绑定起作用?

【问题讨论】:

  • 在 sqlalchemy 中你可以使用 func。示例 - func.DATE(您的日期值作为字符串)

标签: python sqlite sqlalchemy


【解决方案1】:

您需要将 dt 字符串转换为日期对象,例如:

import datetime
for item in data:
    item['dt'] = datetime.datetime.strptime(item['dt'], "%Y-%m-%d").date()

如果您不需要 SQLAlchemy 的 ORM 部分(无类/表映射)。最简单的方法是告诉 SQLAlchemy 你使用 String 而不是 Date,像这样:

tbl1 = Table('t1', metadata,
    Column('the_id', Integer, primary_key=True),
    Column('the_dt', String))

它会起作用,因为您的日期字符串使用 ISO 8601 格式(“%Y-%m-%d”)。

但最佳做法是:

  1. 从 CSV 读取记录
  2. 将数据转换为 Python 对象(intdate 等)
  3. 在数据库中插入数据。

转换可以在映射到表的类的构造函数中完成。

EDIT一种“解决方案”

from sqlalchemy import Table, Column, Integer, MetaData, Date, String
from sqlalchemy import create_engine
from sqlalchemy.sql import select

engine = create_engine('sqlite:///:memory:', echo=True)

metadata = MetaData()

我用String 类型而不是Date 创建了一个“假”表:

fake_tbl1 = Table('t1', metadata,
                  Column('id', Integer, primary_key=True),
                  Column('dt', String))

metadata.create_all(bind=engine)

并按原样插入数据:

data = [
    {'id': 1, 'dt': '2002-01-02'},
    {'id': 2, 'dt': '2014-01-15'},
    {'id': 3, 'dt': '2005-10-20'}
]

stmt_insert = fake_tbl1.insert()

with engine.connect() as conn:
    conn.execute(stmt_insert, data)

然后我用必需的Date 字段重新定义同一个表:

tbl2 = Table('t1', metadata,
             Column('id', Integer, primary_key=True),
             Column('dt', Date),
             extend_existing=True)

这是一个行选择:

stmt_select = select([tbl2])

with engine.connect() as conn:
    result = conn.execute(stmt_select)

for row in result:
    print(row)

你会得到:

(1, datetime.date(2002, 1, 2))
(2, datetime.date(2014, 1, 15))
(3, datetime.date(2005, 10, 20))

这适用于您的简单案例,但我不建议将其用于通用解决方案。

【讨论】:

  • 是的,我已经这样做了。但我想知道是否有某种方法可以使用 sqlalchemy bindparam 函数
  • 为什么不使用类/表映射?
  • 因为,我的要求是从 csv 文件导入数据,我不需要 SQLAlchemy 的 ORM 部分。也只是单纯的好奇:o)
  • 另外,看看SQL Expression Language Tutorial。特别是主题“执行多个语句”。
  • 是的,我在发帖后意识到了这一点;-)。那么,你看到我的编辑一种“解决方案”了吗?
猜你喜欢
  • 2014-10-31
  • 2020-08-21
  • 2017-05-27
  • 1970-01-01
  • 2020-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-24
相关资源
最近更新 更多