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

时间:2016-11-30 19:14:01

标签: python sql sql-server python-3.x pymssql

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

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

1 个答案:

答案 0 :(得分:1)

  

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

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

因此,您只需从源表中获取行列表(包含相应类型的值),并将这些行用作目标表上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)