Pandas to_sql写入PostgreSQL时数据带{}花括号问题解决方案
问题产生原因
PostgreSQL中字段值被{}花括号包裹是数组类型的标准存储表现,该问题由写入时的数据类型不匹配导致:
- 代码中
re.findall()的返回值固定为Python列表类型,即使仅匹配到1个结果,也会返回单元素列表(即控制台打印的['$3.291']格式)。直接将该列表作为价格字段值写入DataFrame时,pandas结合SQLAlchemy写入PostgreSQL的过程中,会自动将Python列表映射为PostgreSQL数组类型(TEXT[]或NUMERIC[]),数组类型的查询输出默认以{}包裹内部元素。 - DataFrame初始化逻辑存在缺陷:初始给价格列传入的是字符串类型测试值
"price",后续循环写入时又传入列表类型值,列类型混杂会干扰pandas的类型推断逻辑,提升类型映射错误概率。 - 代码存在两处冗余/不规范写法:
df.head()仅做打印输出无赋值操作,不会对数据产生实际修改;df.to_sql()执行完成后才新建psycopg2连接查询数据,若to_sql传入的conn是psycopg2原生连接而非SQLAlchemy引擎连接,会进一步提高类型推断的出错概率。
规避与修复方法
- 提取价格时将列表转为标量值,禁止直接存入
re.findall()返回的列表。由于单条商品数据仅对应一个价格,直接取匹配结果的首元素即可,同时增加兜底逻辑避免无匹配结果时触发索引报错:
numbers = re.findall(r'(?:[\£\$\€]{1}[,\d]+.?\d*)', justText) # 取首个匹配到的价格,无匹配结果时赋值为空 price = numbers[0] if numbers else None
后续DataFrame赋值时传入处理后的标量price,替换原来的numbers参数:
df.loc[justText[:pos]] = [justText[:pos], price]
- 修正DataFrame初始化逻辑,删除无意义的测试占位行,直接定义空表明确列结构,避免脏数据和类型混乱:
# 替换原来带测试数据的初始化代码 df = pd.DataFrame(columns=['Product Name', 'Product Price'])
- 写入数据库前强制指定列类型,从根源避免类型自动推断偏差。如果需要保留带货币符号的价格文本,可将价格列强制转为字符串类型;如果需要后续做数值计算,可进一步清洗掉货币符号、千分位分隔符后转为浮点数:
# 保留文本格式时使用 df['Product Price'] = df['Product Price'].astype(str)
- 规范数据库连接使用:
df.to_sql()方法要求传入SQLAlchemy创建的引擎连接,不要直接传入psycopg2生成的原生连接,避免类型映射逻辑异常。
内容的提问来源于stack exchange,提问作者Guilherme Zago
相关产品推荐
相关产品推荐

