You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas+SQLAlchemy将Datetime转为Date加载至SQL Server的问题

解决Pandas加载数据到SQL Server时仅保留日期部分的问题

我明白你遇到的困扰了——用dt.floor('d')或dt.normalize()处理后,SQL Server里要么显示带00:00的完整datetime,要么列被转成字符串。核心原因是Python的datetime.datetime本身没有纯日期的概念,即使时间部分为0,它依然是datetime类型;而Pandas默认的datetime64[ns]类型也会保留时间戳结构。要让SQL Server真正存储纯日期,需要从两个关键环节调整:


1. 将Pandas列转换为纯date对象类型

把datetime64类型的列转换成Python原生的datetime.date对象,彻底剥离时间部分。修改LoadData里的处理逻辑:

df['uplod_tmstp'] = df['uplod_tmstp'].dt.date

这一步会把每一行的时间戳从datetime.datetime(2020,5,5,0,0)变成datetime.date(2020,5,5),完全去除时间信息。

2. 调整sqlcol函数,正确识别date类型

转换后的列在Pandas里的dtype会变成object(因为存储的是Python原生对象),原来的函数只检查datetime类型,会误把它当成字符串处理。我们需要增加判断逻辑,识别存储date对象的列:

首先记得导入datetime模块:

import datetime

然后修改sqlcol函数:

def sqlcol(df):
    dtypedict = {}
    for c in df:
        col_dtype = str(df[c].dtype)
        if 'object' in col_dtype:
            # 检查列是否存储的是date对象
            if len(df[c]) > 0 and isinstance(df[c].iloc[0], datetime.date):
                dtypedict.update({c: sa.types.Date()})
            else:
                # 处理普通字符串列,默认长度50避免空值报错
                max_len = df[c].map(len).max() if len(df[c]) > 0 else 50
                dtypedict.update({c: sa.types.NVARCHAR(length=max_len)})
        elif "datetime" in col_dtype:
            dtypedict.update({c: sa.types.Date()})
    return dtypedict

完整修改后的代码

import sqlalchemy as sa
import pandas as pd
import pyodbc
import urllib
import datetime  # 新增导入

class myengine(object):
    def engine():
        params = urllib.parse.quote_plus("DRIVER={SQL Server Native Client 11.0};" "SERVER=myserver;" "DATABASE=DB1;" "Trusted_Connection=yes;")
        engine = sa.create_engine("mssql+pyodbc:///?odbc_connect={}".format(params),echo=True)
        @sa.event.listens_for(engine, 'before_cursor_execute')
        def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
            if executemany:
                cursor.fast_executemany = True
                cursor.commit()
        return engine

def sqlcol(df):
    dtypedict = {}
    for c in df:
        col_dtype = str(df[c].dtype)
        if 'object' in col_dtype:
            # 识别date对象列
            if len(df[c]) > 0 and isinstance(df[c].iloc[0], datetime.date):
                dtypedict.update({c: sa.types.Date()})
            else:
                max_len = df[c].map(len).max() if len(df[c]) > 0 else 50
                dtypedict.update({c: sa.types.NVARCHAR(length=max_len)})
        elif "datetime" in col_dtype:
            dtypedict.update({c: sa.types.Date()})
    return dtypedict

def LoadData (f):
    df = pd.read_csv(f, dtype='str',parse_dates=['uplod_tmstp'])
    # 转换为纯date对象
    df['uplod_tmstp'] = df['uplod_tmstp'].dt.date
    df.to_sql('Myable', myengine.engine() , if_exists='replace', schema='dbo', index=False, chunksize=1000, dtype=sqlcol(df))

if __name__ == "__main__":
    LoadData('test.csv')

为什么这样有效?

  • dt.date直接生成纯日期对象,彻底移除时间信息;
  • 修改后的sqlcol函数能正确识别这类列,并指定SQL Server的Date类型,确保写入数据库时不会带上时间部分;
  • 避免了字符串转换的问题,保持了日期的原生类型,方便后续SQL查询时的日期操作。

内容的提问来源于stack exchange,提问作者Tyger Guzman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 21:12:52