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

Convert query result types when using fetchall()

我正在编写针对 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)

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

For example I would need the convert the list ... into the [literal] SQL INSERT statement ...

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

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

# 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)