使用 fetchall() 时转换查询结果类型

Posted

技术标签:

【中文标题】使用 fetchall() 时转换查询结果类型【英文标题】:Convert query result types when using fetchall() 【发布时间】:2016-11-30 19:14:00 【问题描述】:

我正在编写一个针对 Microsoft SQL Server 2012 实例的 Python 数据库数据备份脚本。我的目标是能够轻松地将数据库的数据备份到现有的空模式。我使用 pymssql 作为我的数据库接口。

这是我遇到问题的代码部分:

def run_migrate(s_conn, d_conn): 
    source_cursor = s_conn.cursor()
    dest_cursor = d_conn.cursor()
    source_cursor.execute("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES order by TABLE_NAME asc")
    res_tables = source_cursor.fetchall()
    tables = [i[0] for i in res_tables]
    for i in range(len(tables)): 
        query_columns = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" + str(tables[i]) + "'"
        l.log.debug(query_columns)
        source_cursor.execute(query_columns)
        res_columns = source_cursor.fetchall()
        columns = [i[0] for i in res_columns]
        query_data = 'SELECT * FROM ' + tables[i]
        l.log.debug(query_data)
        source_cursor.execute(query_data)
        res_results = source_cursor.fetchall()
        l.log.info('Extracted ' + str(len(results))  + ' results from ' + tables[i])

我的问题是,当我使用 res_results = fetchall() 时,我得到一个如下所示的列表:

<class 'list'>: [(Decimal('102'), datetime.datetime(2016, 3, 29, 13, 53, 20, 593000), '1459281200561077E9152BF85FCBC33E6689E9DCB61705985137701459280466827', 'cable summary ', 3600000, 0, None, None, None, None, None, None, 0, 0, None, None, Decimal('333'), Decimal('100'), Decimal('107'), None, None)]

我希望从这些数据中形成一个参数化的 INSERT 语句以针对 d_conn.execute() 运行,但是如何在不事先知道每个列的数据类型以及如何处理它的情况下即时转换数据类型?

例如我需要转换列表:

<class 'list'>: [
(Decimal('102'), 
datetime.datetime(2016, 3, 29, 13, 53, 20, 593000),
'1459281200561077E9152BF85FCBC33E6689E9DCB61705985137701459280466827', 
'cable summary ', 
3600000, 
0, 
None, 
None, 
None, 
None, 
None, 
None, 
0, 
0, 
None, 
None, 
Decimal('333'), 
Decimal('100'), 
Decimal('107'), 
None, 
None)]

进入 SQL INSERT 语句:

INSERT INTO [ALERT] VALUES
   (102
   ,'2016-03-29 13:53:20.593'
   ,1
   ,'cable summary'
   ,3600000
   ,0
   ,NULL
   ,NULL
   ,NULL
   ,NULL
   ,NULL
   ,NULL
   ,0
   ,0
   ,NULL
   ,NULL
   ,333
   ,100
   ,107
   ,NULL
   ,NULL)

我希望能够使用我传递的任何数据类型来执行此操作,因为我有数百个表可以执行此操作,并且不想为每个表编写一个函数。任何帮助表示赞赏。

【问题讨论】:

使用原力和 ORM,卢克。 sqlalchemy 是轻量级的,并且支持 pymssql。 【参考方案1】:

例如,我需要将列表 ... 转换为 [literal] SQL INSERT 语句 ...

实际上,不,您不会,至少如果您确实对 INSERT 使用了参数化查询,则不会。 Python 的 DB-API 指定通用参数占位符并依赖数据库访问层(例如 pymssql)来确定如何根据提供的参数 values 的类型来处理参数。

因此,您可以简单地从源表中获取行列表(其中包含适当类型的值),并将这些行用作目标表上 executemany 的参数值,如下所示:

# set up test
create_stmt = """\
CREATE TABLE  (
    intCol INT PRIMARY KEY,
    nvarcharCol NVARCHAR(50),
    datetimeCol DATETIME,
    decimalCol DECIMAL(18,4),
    nullableCol INT
    )
"""
crsr.execute(create_stmt.format("#MainTable"))
load_test_data = """\
INSERT INTO #MainTable (intCol, nvarcharCol, datetimeCol, decimalCol) VALUES
    (1, N'test 1', '2016-01-01', 1.11),
    (2, N'test 2', '2016-02-02', 2.22),
    (3, N'test 3', '2016-03-03', 3.33)
"""
crsr.execute(load_test_data)
crsr.execute(create_stmt.format("#BackupTable"))

# perform the copy ...
read_stmt = """\
SELECT * FROM #MainTable
"""
crsr.execute(read_stmt)
source_rows = crsr.fetchall()
# ... using a true parameterized query ...
write_stmt = """\
INSERT INTO #BackupTable
        (intCol, nvarcharCol, datetimeCol, decimalCol, nullableCol)
    VALUES
        (%s, %s, %s, %s, %s)
"""
# ... inserting all rows at once using list returned by fetchall() from source table
crsr.executemany(write_stmt, source_rows)

#check results
crsr.execute("SELECT * FROM #BackupTable")
print("Rows from #BackupTable:")
for row in crsr.fetchall():
    print(row)

...生产:

Rows from #BackupTable:
(1, 'test 1', datetime.datetime(2016, 1, 1, 0, 0), Decimal('1.1100'), None)
(2, 'test 2', datetime.datetime(2016, 2, 2, 0, 0), Decimal('2.2200'), None)
(3, 'test 3', datetime.datetime(2016, 3, 3, 0, 0), Decimal('3.3300'), None)

【讨论】:

以上是关于使用 fetchall() 时转换查询结果类型的主要内容,如果未能解决你的问题,请参考以下文章

数据库查询操作(fetchone,fetchall)

python 中cursor的用法

既然不推荐使用 fetchAll() 和 FetchMode,如何将结果提取到自定义对象中?

关于python中的查询数据库内容中用到的fetchone()函数和fetchall()函数(转)

SQL.fetchall() 使用 Python 失败,出现 SQLState 24000(无效游标状态)

SQLAlchemy 在使用 fetchall 方法迭代结果后提交 sql 执行