sqlite3 returns 日期时间的字节字符串

sqlite3 returns byte string for datetime

我有一个sqlite3数据库:

import sqlite3
import pandas as pd
from datetime import datetime

batch_size = 10

con = sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
cur = con.cursor()

table = """CREATE TABLE my_table(DateCreated DATETIME);"""
cur.execute(table)

DateCreated = [datetime(2020, 12, 1, 1, 1)] * batch_size
x = list(pd.DataFrame({'DateCreated':DateCreated}).to_records(index=False))

query = """INSERT INTO my_table (DateCreated) values (?);"""

cur.executemany(query, x)

当我想检索我的日期时间时,sqlite3 returns 字节字符串而不是日期时间对象:

cur.execute("SELECT * FROM my_table;")
cur.fetchone()
>> (b'\x00\xf8\xea\x08\xf4qL\x16',)

我做错了什么?我检查了 this issue 但它并不真正适用于我的问题。我还尝试将 sqlite 数据类型从 DATETIME 更改为 TIMESTAMP,但收到 ValueError: not enough values to unpack (expected 2, got 1)。我正在使用 Python 3.8.10.

问题在于我使用了 pandas' .to_record() 方法。如果我删除该步骤并提供 元组 列表而不是 numpy 记录 列表,则数据库 returns 日期时间正确.

import sqlite3
import pandas as pd
from datetime import datetime

batch_size = 10

con = sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
cur = con.cursor()

table = """CREATE TABLE my_table(DateCreated DATETIME);"""
cur.execute(table)

DateCreated = [(datetime(2020, 12, 1, 1, 1),)] * batch_size

query = """INSERT INTO my_table (DateCreated) values (?);"""

cur.executemany(query, DateCreated)

cur.execute("SELECT * FROM my_table;")

cur.fetchall()

您的代码片段中有两个错误:sqlite3 列的正确数据类型是 timestamp,而不是 datetime。 Sqlite3 很奇特,它只接受任何内容并将所有内容在内部存储为字符串 - 它是 Python 驱动程序,它将以不同方式处理列类型“时间戳”,并且能够直接接受和检索日期时间对象。

也就是说,“df.to_record”调用也无济于事,因为它将 pandas 日期时间检索为字符串。正确的做法是检索每个 pandas 单元格值并对其调用 .to_pydatetime()

因此,如果您需要将示例中未给出的另一个数据框转换为 sqlite,则此类代码有效:

import sqlite3
import pandas as pd
from datetime import datetime

batch_size = 10

con = sqlite3.connect(':memory:', detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
cur = con.cursor()

table = """CREATE TABLE my_table(DateCreated timestamp)"""
cur.execute(table)

DateCreated = [datetime(2020, 12, 1, 1, 1)] * batch_size
x = [(rec.to_pydatetime(),)  for rec in  pd.DataFrame({'DateCreated':DateCreated})["DateCreated"]]

query = """INSERT INTO my_table (DateCreated) values (?)"""
cur.executemany(query, x)

我在上面编写 x = 表达式的方式将允许您从数据框中 select 所需的列,并仅在所需的字段中调用 .to_pydatetime()

如果您的数据框有 5 个其他列,并且日期时间在第 3 个 [index 2],这有效:

x = [(*rec[0:2], rec[2].to_pydatetime(), *rec[3:])  for _, rec in df.iterrows()]

而且,如果您根本不从 pandas 工作流程转换内容,则无需干预,只需将日期时间对象创建为元组并将其插入即可:

x = [(datetime.now(),) for i in range(10)]