python——执行带有%的sql执行报错解决方法

本文介绍了一种使用Pandas从PostgreSQL读取数据时遇到的问题及解决方案。当SQL语句中包含'%'字符时,由于它是psycopg的占位符,直接使用pd.read_sql_query会引发错误。通过使用text(sql)方法可以有效避免此问题。
部署运行你感兴趣的模型镜像

from sqlalchemy import create_engine, text

今天在使用pandas的pd.read_sql_query(sql,engine)方法读取pg库字段时报错,'dict' object does not support indexing。

原因:

查了一下,原因是sql语句包含'%',这是psycopg语法中的占位符,不做处理会报错。

解决方案:

可以使用pd.read_sql_query(text(sql),engine)解决,就是第一句中import的text。

您可能感兴趣的与本文相关的镜像

Python3.11

Python3.11

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

你在使用 **SQLAlchemy** 执行原生 SQL 时,尝试使用 `%s` 作为占位符,结果报错: ``` Mapping or list expected for parameters ``` 这是由于你 **混淆了不同数据库驱动的参数绑定语法** 导致的。下面我们详细解释这个问题的原因、正确做法,并提供 Java 类比说明。 --- ### ❌ 错误原因:使用 `%s` 而不是 SQLAlchemy 支持的参数风格 SQLAlchemy 的 `connection.execute(text(sql), params)` 方法默认使用 **命名参数或位置参数(基于 DBAPI 标准)**,但 **不支持 MySQL 风格的 `%s` 占位符**,除非你使用的是特定方言且传参方式匹配。 #### 常见错误写法: ```python sql = "SELECT * FROM users WHERE id = %s" connection.execute(text(sql), [1]) # 报错! ``` 即使你的数据库是 MySQL,**在配合 `text()` 使用时也不能直接用 `%s`**,因为 SQLAlchemy 并不知道你要用的是 `pyformat` 参数风格(即 `%s`),它期望的是统一的参数结构。 --- ### ✅ 正确解决方案 #### ✅ 方案一:使用 `:name` 命名占位符(推荐) ```python from sqlalchemy import text sql = text("SELECT * FROM users WHERE id = :id") result = connection.execute(sql, {"id": 1}) rows = result.fetchall() ``` ✅ 这是 SQLAlchemy 官方推荐的方式 —— 使用冒号前缀的命名参数。 --- #### ✅ 方案二:使用 `?`(仅适用于支持该语法的数据库,如 SQLite) ```python sql = text("SELECT * FROM users WHERE id = ?") result = connection.execute(sql, [1]) ``` 注意:这种方式只在底层驱动支持 `?` 占位符时有效(例如 SQLite)。MySQL 的 `pymysql` 或 `mysql-connector` 不支持 `?`,而 PostgreSQL 的 `psycopg2` 也不推荐用 `?`。 --- #### ✅ 方案三:如果你坚持要用 `%s`,必须确保: 1. 使用的是 MySQL + PyMySQL/MySQLdb; 2. 不使用 `text()` 包装; 3. 使用正确的参数格式(pyformat); 但实际上,在 SQLAlchemy 中你应该始终优先使用 `:param` 风格。 > 🔁 SQLAlchemy 内部会根据数据库方言自动将 `:param` 转换为对应数据库的正确语法(比如转换成 `%s` 或 `$1`),所以你不需要手动写 `%s`。 --- ### 🔍 Java 类比理解 这类似于 Java 中使用 `PreparedStatement`: ```java String sql = "SELECT * FROM users WHERE id = ?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setInt(1, 1); ResultSet rs = ps.executeQuery(); ``` 你不会在 Java 中这样写: ```java // 错误!不能直接拼接 String sql = "SELECT * FROM users WHERE id = " + userId; // SQL 注入风险 ``` 同理,在 SQLAlchemy 中你不应使用 `%s` 字符串格式化,而应使用参数绑定机制。 --- ### ⚠️ 绝对禁止的做法(危险!) ```python # 千万不要这样做!! user_input = 1 sql = f"SELECT * FROM users WHERE id = %s" % user_input connection.execute(text(sql)) # 即使不报错,也有 SQL 注入风险! ``` 这不仅可能触发错误,还会导致 **SQL 注入漏洞**。 --- ### 总结:如何修复? | 问题 | 解决方案 | |------|----------| | 使用 `%s` 报错 | 改为使用 `:param` 命名参数 | | 参数类型错误 | 确保传入的是字典 `{}` 或列表 `[]`,而不是单独一个值 | | 想要动态 IN 查询 | 使用 `:param` + 列表参数,SQLAlchemy 会自动展开 | #### 正确示例(带 IN 查询): ```python ids = [1, 2, 3] sql = text("SELECT * FROM users WHERE id IN :ids") result = connection.execute(sql, {"ids": ids}) ``` ⚠️ 注意:对于 `IN :ids`,SQLAlchemy 会自动将其展开为 `(?, ?, ?)` 形式,无需你手动处理。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值