如何在pyodbc输出转换器函数中解压缩SQL Server DATETIME? - python

我将输出转换器添加到pyodbc连接对象,以处理从SQL Server返回的日期类型。我能够使用以下命令解压缩datetime.time结构:

tuple   = struct.unpack("HHHI", dateObj)

效果很好。我无法弄清楚datetime.datetime对象的秘密之处,根据pyodbc文档,它是TIMESTAMP_STRUCT,定义为here:

typedef struct tagTIMESTAMP_STRUCT
{
        SQLSMALLINT    year;
        SQLUSMALLINT   month;
        SQLUSMALLINT   day;
        SQLUSMALLINT   hour;
        SQLUSMALLINT   minute;
        SQLUSMALLINT   second;
        SQLUINTEGER    fraction;
} TIMESTAMP_STRUCT;

来自数据库中该列的基准是2018-01-11 11:50:16.000,并且没有add_output_convert陷阱,pyodbc返回:

TypeError: datetime.datetime(2018, 1, 11, 11, 50, 16) is not JSON serializable

看起来pyodbc默默地丢弃了分数,这很好。 unpack()格式不应该是以下之一:

tuple = struct.unpack("hHHHHHI", dateObj)  # with missing fraction
tuple = struct.unpack("hHHHHH", dateObj)

?后者只是返回:

error: unpack requires a string argument of length 12

对于记录,根据sys.getsizeof dateObj是41个字节。对格式有什么建议吗?这是Windows 10 64位以及Linux 64位。

参考方案

您似乎一直在寻找一些错误的线索。 SQL Server ODBC驱动程序不为DATETIME值返回41字节的数据,它仅返回8字节。 (sys.getsizeof返回值41,因为它包含与垃圾回收相关的“开销”。)而且这8个字节无法表示TIMESTAMP_STRUCT,因此它必须是其他值。

从基本测试开始...

import pyodbc


def datetime_as_string(raw_bytes):
    return raw_bytes


cnxn = pyodbc.connect('DSN=SQLmyDb;', autocommit=True)
cnxn.add_output_converter(pyodbc.SQL_TYPE_TIMESTAMP, datetime_as_string)
crsr = cnxn.cursor()

test_value = '2018-01-11 11:50:16'
rtn = crsr.execute("SELECT CAST(? AS DATETIME)", test_value).fetchval()
print(repr(rtn))

crsr.close()
cnxn.close()

...我看到您的测试值由'e\xa8\x00\x00\xa0\x14\xc3\x00'表示。在Windows计算器中使用十六进制转换器的一些时间告诉我,内容不是立即显而易见的。打个预感,我尝试了test_value = '1900-01-01 00:00:00',然后返回了'\x00\x00\x00\x00\x00\x00\x00\x00',所以至少我有一个开始的地方(SQL Server DATETIME值的“历元”)。

test_value = '1901-01-01 00:00:00'(历经1年)返回了'm\x01\x00\x00\x00\x00\x00\x00''m'0x6d0x016d是365,所以这令人鼓舞。

test_value = '1900-01-01 00:00:01'(历时后1秒)返回'\x00\x00\x00\x00,\x01\x00\x00'','0x2c0x012c是300。

test_value = '1900-01-01 00:00:02'(历时2秒后)返回'\x00\x00\x00\x00X\x02\x00\x00''X'0x580x0258是600。

因此,SQL Server ODBC驱动程序将返回两个4字节带符号整数,第一个是整天与纪元的偏移量,第二个是部分天,以1/300秒为增量。

因此我将输出转换器功能更改为

def datetime_as_string(raw_bytes):
    tup = struct.unpack("<2l", raw_bytes)
    days_since_1900 = tup[0]
    partial_day = round(tup[1] / 300.0, 3)
    date_time = datetime(1900, 1, 1) + timedelta(days=days_since_1900) + timedelta(seconds=partial_day)
    return date_time.strftime('%Y-%m-%d %H:%M:%S.%f')[:23]

这似乎可以解决问题。

使用Python从数据库中提取 - python

我用Python编写了一个小脚本,可以帮助我从数据库中提取数据。这是我的脚本:#!/usr/bin/python3 import pandas as pd from sqlalchemy import create_engine #connect to server mytab = create_engine('mssql+pyodbc://tes…

在返回'Response'(Python)中传递多个参数 - python

我在Angular工作,正在使用Http请求和响应。是否可以在“响应”中发送多个参数。角度文件:this.http.get("api/agent/applicationaware").subscribe((data:any)... python文件:def get(request): ... return Response(seriali…

Python exchangelib在子文件夹中读取邮件 - python

我想从Outlook邮箱的子文件夹中读取邮件。Inbox ├──myfolder 我可以使用account.inbox.all()阅读收件箱,但我想阅读myfolder中的邮件我尝试了此页面folder部分中的内容,但无法正确完成https://pypi.python.org/pypi/exchangelib/ 参考方案 您需要首先掌握Folder的myfo…

R'relaimpo'软件包的Python端口 - python

我需要计算Lindeman-Merenda-Gold(LMG)分数,以进行回归分析。我发现R语言的relaimpo包下有该文件。不幸的是,我对R没有任何经验。我检查了互联网,但找不到。这个程序包有python端口吗?如果不存在,是否可以通过python使用该包? python参考方案 最近,我遇到了pingouin库。

在远程节点上执行bash脚本,并通过python从服务器进行控制 - python

我有两个设备,一个是Server,另一个是Linux NODE。 NODE没有python解释器。服务器 NODE我想在由服务器从Python程序触发的NODE中远程执行bash脚本。我应该将bash脚本的输出返回到我的Python脚本。请让我知道该怎么做。 参考方案 如果您能够在服务器和节点之间进行SSH,那么paramiko可能是您的答案。在您的设置中,…