Python导入SQL Server数据至Google Sheets报错:Row无法JSON序列化
解决pyodbc Row对象无法序列化到Google Sheets的问题
问题根源
从SQL Server导出数据到Google Sheets时触发TypeError: Object of type Row is not JSON serializable,原因有两点:
- pyodbc的
cursor.fetchall()返回的是Row对象列表,而非Google Sheets API可识别的普通Python数据结构 - Row对象中包含
Decimal、datetime这类无法直接JSON序列化的特殊类型
解决方案
1. 转换Row对象为可序列化的普通列表
遍历查询结果,将每个Row转为普通列表,同时处理特殊类型:
Decimal:转为float(或字符串保留精度)datetime:转为ISO格式字符串,方便Google Sheets自动识别为日期
2. 批量写入优化性能
80万条数据循环写入效率极低,建议用批量更新方法替代逐行写入,避免触发API配额限制。
修改后的完整代码
import pyodbc import gspread from google.oauth2 import service_account from decimal import Decimal import datetime # 数据库连接配置 server = 'xxx.xxx.xxx.xxx, 1433' database = 'DATADB' username = 'XXX_XX' password = 'PASSWORDXXX' cnxn = pyodbc.connect( 'DRIVER={ODBC Driver 17 for SQL Server};SERVER='+server+ ';DATABASE='+database+';UID='+username+';PWD='+ password ) cursor = cnxn.cursor() # 执行查询并获取结果 cursor.execute("SELECT * FROM dbo.cosillastabla") rows = cursor.fetchall() # 处理数据:转换Row对象+特殊类型序列化 processed_rows = [] for row in rows: converted_row = [] for item in row: if isinstance(item, Decimal): # 如需保留精确值,替换为 str(item) converted_row.append(float(item)) elif isinstance(item, datetime.datetime): # 转为ISO格式,Google Sheets自动识别为日期 converted_row.append(item.isoformat()) else: converted_row.append(item) processed_rows.append(converted_row) # Google Sheets授权 SERVICE_ACCOUNT_FILE = 'keys.json' SCOPES = ['https://www.googleapis.com/auth/spreadsheets'] SAMPLE_SPREADSHEET_ID = 'kjsdfkjfjksdjkfsdfsdhfsdkjfhsjf' credentials = service_account.Credentials.from_service_account_file( SERVICE_ACCOUNT_FILE, scopes=SCOPES ) # 使用gspread批量写入(简洁易维护) gc = gspread.authorize(credentials) sheet = gc.open_by_key(SAMPLE_SPREADSHEET_ID).worksheet('temilla') # 从B2单元格开始写入二维列表数据 sheet.update('B2', processed_rows, value_input_option='USER_ENTERED') # (可选)使用Sheets API批量写入(适合精细控制场景) # service = build('sheets', 'v4', credentials=credentials) # sheet_service = service.spreadsheets() # request = sheet_service.values().update( # spreadsheetId=SAMPLE_SPREADSHEET_ID, # range='temilla!B2', # valueInputOption='USER_ENTERED', # body={'values': processed_rows} # ).execute() # 关闭数据库连接 cursor.close() cnxn.close()
注意事项
- 80万条数据属于大体积数据,建议分批次写入(比如每10000条一批),避免触发Google API的配额限制
- 若需保留Decimal的精确数值,将
float(item)替换为str(item),后续可在Google Sheets中手动转换为数字格式 - 原代码中混用了Sheets API响应对象和gspread方法(
request.append_row),这是错误用法,需统一使用一种操作方式
内容的提问来源于stack exchange,提问作者Fabrisimo
相关产品推荐
相关产品推荐

