使用SQLAlchemy向SQL Server插入日期时遇类型转换失败问题
问题原因及解决方案
核心问题:creation_date字段默认值配置错误
你遇到的日期转换失败错误,根源在于数据库表creation_date字段的默认值被设置成了字符串'func.now()',而非SQL Server可识别的日期函数:
- 模型中你想通过
server_default="func.now()"让数据库自动填充当前时间,但SQL Server的当前时间函数是GETDATE(),而非func.now()(这是MySQL的语法)。 - 实际执行的建表SQL里,你给
creation_date添加的默认值是DEFAULT ('func.now()')——数据库会把这个字符串当作日期值来解析,'func.now()'显然不是合法的日期格式,因此插入时触发转换失败错误。
其他次要问题
- 模型与数据库表名不匹配:模型类
ScenarioTrainingSchedule的__tablename__是scenario_training_schedule,但你实际创建的数据库表是schedule,插入代码又用了Schedule类,三者不一致会导致ORM操作混乱。 - 插入代码语法错误:创建对象时多了一个右括号,正确的对象创建语法应该是
Schedule(company_id=1, scenario_id='practice', training_date=...),而非带多余括号的写法。 - 原生SQL未规避默认值问题:即使你用了合法的
DATEFROMPARTS生成日期,但creation_date的错误默认值依然会触发转换失败。
修复步骤
1. 修正creation_date的数据库默认值
先删除错误的默认值约束,再添加正确的SQL Server时间函数默认值:
-- 先查询表的默认值约束名(替换成你的表名) EXEC sp_helpconstraint 'schedule'; -- 删除错误约束(替换成查询到的约束名) ALTER TABLE [schedule] DROP CONSTRAINT DF__schedule__creati__xxxxxx; -- 添加正确的默认值 ALTER TABLE [schedule] ADD DEFAULT (GETDATE()) FOR [creation_date];
同时同步修正模型类的server_default配置,适配SQL Server:
from sqlalchemy import text class ScenarioTrainingSchedule(Base): __tablename__ = "schedule" # 统一表名,和数据库表一致 id = Column(Integer, primary_key=True) company_id = Column(Integer, nullable=False) scenario_id = Column(String, nullable=False) training_date = Column(Date, nullable=False) creation_date = Column(DateTime, nullable=False, server_default=text("GETDATE()"))
2. 修正插入代码的语法错误
确保类名、参数格式正确,并提交会话:
from datetime import datetime # 用正确的模型类名,参数格式无语法错误 training = ScenarioTrainingSchedule( company_id=1, scenario_id='practice', training_date=datetime.strptime('2020-01-01', '%Y-%m-%d').date() ) session.add(training) session.commit() # 必须提交会话才能写入数据库
3. 验证原生SQL插入
修复默认值后,原生SQL可以正常执行,也可显式指定creation_date避免依赖默认值:
INSERT INTO schedule (company_id, scenario_id, training_date, creation_date) VALUES (12, 'practice', DATEFROMPARTS(YEAR(GETDATE()), 1, 1), GETDATE());
内容的提问来源于stack exchange,提问作者RogerKint
相关产品推荐
相关产品推荐

