from re import match import mysql.connector import requests from bs4 import BeautifulSoup from mysql.connector import errorcode headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36'} conn = mysql.connector.connect( host="localhost", user="root", password="123456", database="test" ) cursor = conn.cursor() def create_tables(): tables = { 'students': ( "CREATE TABLE students (" "id INT AUTO_INCREMENT PRIMARY KEY," "name VARCHAR(50) NOT NULL," "sex VARCHAR(50) NOT NULL," "age INT" ")" ), 'class': ( "CREATE TABLE class (" "id INT AUTO_INCREMENT PRIMARY KEY," "class_name VARCHAR(50) NOT NULL," "class_score INT" ")" ), 'score': ( "CREATE TABLE score (" "id INT AUTO_INCREMENT PRIMARY KEY," "student_id INT NOT NULL," "class_id INT NOT NULL," "score DECIMAL(5,2) CHECK (score BETWEEN 0 AND 100)," "FOREIGN KEY (student_id) REFERENCES students(id)" " ON UPDATE CASCADE ON DELETE RESTRICT," # 注意逗号分隔 "FOREIGN KEY (class_id) REFERENCES class(id)" " ON UPDATE CASCADE ON DELETE RESTRICT" ")" ) } try: # 按依赖顺序创建表 cursor.execute(tables['students']) cursor.execute(tables['class']) cursor.execute(tables['score']) conn.commit() print("表创建成功") except mysql.connector.Error as err: if err.errno == errorcode.ER_TABLE_EXISTS_ERROR: print("表已存在") else: print(f"创建失败: {err.msg}") def insert_student(table, data): try: sql = f"INSERT INTO {table} (id, name, sex, age) VALUES ((%s, %s, %s, %s)" cursor.executemany(sql, data) conn.commit() except mysql.connector.Error as err: # 打印出错误信息和当前尝试执行的SQL语句 print(f"SQL语句: {sql}") print(f"错误信息: {err.msg}") def insert_score(table, data): try: sql = f"INSERT INTO {table} (student_id, class_id, score) VALUES ((%s, %s, %s)" cursor.executemany(sql, data) conn.commit() except mysql.connector.Error as err: # 打印出错误信息和当前尝试执行的SQL语句 print(f"SQL语句: {sql}") print(f"错误信息: {err.msg}") def get_data(url): re = requests.get(url, headers=headers).json() students = [] scores = [] for i in range(2,len(re)): stu = [re[i][0], re[i][1], re[i][2], re[i][3]] students.append(stu) if re[i][4] == '语文': sco = [re[i][0], 1, re[i][5]] scores.append(sco) if re[i][4] == '英语': sco = [re[i][0], 2, re[i][5]] scores.append(sco) if re[i][4] == '数学': sco = [re[i][0], 3, re[i][5]] scores.append(sco) print([x for i, x in enumerate(students) if x not in students[:i]]) print(scores) insert_student('students',[x for i, x in enumerate(students) if x not in students[:i]]) insert_score('score',scores) # 执行创建 create_tables() get_data('http://article.xishanyigu.com/index/index/test') 这是我更新后的代码
时间: 2025-07-19 13:27:59 浏览: 6
<think>我们正在处理一个常见的Python与MySQL交互时出现的SQL语法错误问题,特别是INSERT语句中的错误。根据引用内容,主要问题可能出现在字符串中的引号未正确处理,或者使用了不安全的字符串拼接方式。
关键点:
1. 当插入的字符串中包含单引号时,会导致SQL语句提前结束,从而引发语法错误(如引用[1]和引用[3]所述)。
2. 使用参数化查询(如引用[2]所示)可以避免此问题,同时还能防止SQL注入攻击。
3. 如果必须使用字符串拼接,则需要对字符串进行转义(如引用[3]使用escape_string)。
解决方案:
1. 优先推荐使用参数化查询(使用%s作为占位符,然后传递元组或列表给execute或executemany方法)。这种方法不需要手动转义引号,且更安全高效。
2. 如果因为某些原因必须使用字符串拼接,则应对字符串进行转义处理(使用pymysql.escape_string)。
具体步骤:
方法一:参数化查询(推荐)
```python
import pymysql
# 连接数据库
conn = pymysql.connect(host='localhost', user='user', password='passwd', db='test')
cursor = conn.cursor()
# 要插入的数据,注意:这里的数据可以是包含单引号的字符串
data = [
(1, "John's book", "This is John's book."),
(2, "Jane's pen", "Jane said: \"It's my pen!\"")
]
# 使用executemany批量插入
sql = "INSERT INTO your_table (id, title, content) VALUES (%s, %s, %s)"
cursor.executemany(sql, data)
conn.commit()
# 关闭连接
cursor.close()
conn.close()
```
方法二:手动转义(不推荐,除非有特殊原因)
```python
from pymysql import escape_string
# 连接数据库(同上)
# 数据准备
id_val = 1
title = "John's book"
content = "This is John's book."
# 转义字符串
title_escaped = escape_string(title)
content_escaped = escape_string(content)
# 构建SQL语句(注意:字段值需要加单引号,因为转义后的字符串不带引号)
sql = f"INSERT INTO your_table (id, title, content) VALUES ({id_val}, '{title_escaped}', '{content_escaped}')"
cursor.execute(sql)
conn.commit()
# 关闭连接(同上)
```
注意:方法二需要手动添加单引号,且转义后的字符串是安全的。但是,这种方法容易出错且不安全(如果忘记转义),所以强烈推荐使用方法一。
根据引用[2]的信息,使用参数化查询(executemany)不仅安全,而且效率更高(26万条数据只需十几秒,而字符串拼接方式需要1.5小时)。
因此,我们应优先采用参数化查询。
此外,还需要注意:
- 表名和列名如果是保留字,应该用反引号括起来(但参数化查询中,占位符只能用于值,不能用于表名和列名,所以表名和列名需要我们在构造SQL语句时自行确保安全,通常可以通过检查白名单等方式)。
如果用户的问题是由于字符串中的引号引起的,那么采用参数化查询即可解决。
下面我们给出一个完整的示例,展示如何安全地插入包含单引号的数据:
示例代码:
```python
import pymysql
# 数据库连接配置
config = {
'host': 'localhost',
'user': 'your_username',
'password': 'your_password',
'database': 'your_database',
'charset': 'utf8mb4'
}
# 连接数据库
conn = pymysql.connect(**config)
cursor = conn.cursor()
# 示例数据,包含单引号和双引号
data = [
(1, "John's book", 'He said: "This is my book."'),
(2, "Jane's pen", 'She said: "It\'s my pen!"')
]
try:
# 使用参数化查询
sql = "INSERT INTO test_table (id, title, content) VALUES (%s, %s, %s)"
cursor.executemany(sql, data)
conn.commit()
print("插入成功")
except Exception as e:
print(f"插入失败: {e}")
conn.rollback()
finally:
cursor.close()
conn.close()
```
这个示例中,即使字符串中包含单引号或双引号,也不会引起SQL语法错误,因为参数化查询会自动处理这些特殊字符。
如果用户之前使用的是字符串拼接的方法,那么强烈建议切换到参数化查询。
相关问题:
1. 如何防止Python中的SQL注入攻击?
2. 使用参数化查询时,如何插入表名或列名作为变量?
3. 在Python中,如何高效地向MySQL插入大量数据?</think># Python MySQL 插入数据时SQL语法错误的解决方案
当在Python中使用MySQL插入数据时出现SQL语法错误,通常是由于特殊字符处理不当或SQL语句构造问题导致的。下面我将详细解释常见原因并提供解决方案。
## 常见错误原因及解决方案
### 1. 字符串中的引号未正确处理(最常见问题)
当插入的字符串包含单引号(`'`)或双引号(`"`)时,会导致SQL语句提前终止。
**错误示例**:
```python
name = "John's Book"
sql = f"INSERT INTO books (title) VALUES ('{name}')"
# 生成错误SQL: INSERT INTO books (title) VALUES ('John's Book')
```
**解决方案**:使用参数化查询(推荐方法)
```python
import pymysql
conn = pymysql.connect(host='localhost', user='user', password='pass', db='test')
cursor = conn.cursor()
data = ("John's Book",)
cursor.execute("INSERT INTO books (title) VALUES (%s)", data) # 使用%s占位符
conn.commit()
```
### 2. 特殊字符未转义
当插入数据包含特殊字符时,需要使用转义函数处理。
**解决方案**:使用`escape_string()`函数
```python
from pymysql import escape_string
title = "This is a 'test' string"
content = 'Another "example"'
# 转义特殊字符
safe_title = escape_string(title)
safe_content = escape_string(content)
sql = f"INSERT INTO posts (title, content) VALUES ('{safe_title}', '{safe_content}')"
cursor.execute(sql)
```
### 3. 批量插入效率问题
使用`executemany()`可以显著提高批量插入效率。
**解决方案**:高效批量插入
```python
import pymysql
# 准备数据
books = [
("Python Basics", "John Doe"),
("Advanced SQL", "Jane Smith"),
("O'Reilly Guide", "Mike O'Neil") # 包含特殊字符
]
conn = pymysql.connect(host='localhost', user='user', password='pass', db='test')
cursor = conn.cursor()
# 使用executemany进行批量插入
sql = "INSERT INTO books (title, author) VALUES (%s, %s)"
cursor.executemany(sql, books) # 自动处理特殊字符
conn.commit()
```
### 4. 表名或列名是MySQL保留字
当表名或列名与MySQL保留字冲突时,需要使用反引号包裹。
**解决方案**:
```python
# 使用反引号包裹保留字
cursor.execute("INSERT INTO `order` (`select`, `group`) VALUES (%s, %s)", ("item", 1))
```
## 完整解决方案示例
```python
import pymysql
from pymysql import Error
def safe_insert(data_list):
try:
conn = pymysql.connect(
host='localhost',
user='your_user',
password='your_password',
database='your_db',
charset='utf8mb4'
)
with conn.cursor() as cursor:
# 使用参数化查询避免SQL注入和语法错误
sql = """
INSERT INTO `products` (
`name`,
`description`,
`price`
) VALUES (%s, %s, %s)
"""
# 执行批量插入
cursor.executemany(sql, data_list)
conn.commit()
print(f"成功插入 {len(data_list)} 条记录")
return True
except Error as e:
print(f"数据库错误: {e}")
# 详细错误信息
print(f"错误代码: {e.args[0]}")
print(f"错误信息: {e.args[1]}")
return False
finally:
if conn and conn.open:
conn.close()
# 测试数据(包含特殊字符)
products = [
("Laptop", "15' display with 8GB RAM", 999.99),
("Phone", "Water-resistant 'flagship' model", 799.99),
("Tablet", "10\" screen with stylus", 499.99)
]
# 执行插入
safe_insert(products)
```
## 最佳实践建议
1. **始终使用参数化查询**:
- 使用`%s`作为占位符,避免直接拼接字符串
- 让数据库驱动自动处理特殊字符和类型转换
2. **批量操作使用executemany**:
- 比循环执行单条INSERT快10-100倍
- 自动处理事务,要么全部成功要么全部失败
3. **处理特殊字符**:
- 对于必须拼接的情况,使用`pymysql.escape_string()`
- 避免在SQL语句中使用中文或特殊标点
4. **错误处理**:
- 捕获`pymysql.Error`异常
- 记录详细错误信息(错误代码和消息)
- 实现重试机制或回滚事务
5. **连接管理**:
- 使用`with`语句确保连接正确关闭
- 设置合适的字符集(推荐`utf8mb4`)
通过遵循这些最佳实践,您可以避免大多数SQL语法错误,并构建健壮的数据库操作程序。
## 相关问题
1. **如何防止Python中的SQL注入攻击?**
参数化查询是防止SQL注入的最有效方法,因为它将数据与SQL指令分离,确保用户输入不会被解释为SQL代码[^1]。
2. **在Python中批量插入大量数据到MySQL的最优方法是什么?**
使用`executemany`配合参数化查询是最佳方法,对于极大数据集可考虑使用`LOAD DATA INFILE`命令[^2]。
3. **如何处理MySQL中的保留字作为表名或列名?**
使用反引号(`` ` ``)包裹保留字(如`` `order` ``),并在Python代码中保持一致[^1]。
4. **Python连接MySQL时应该使用哪个字符集?**
推荐使用`utf8mb4`字符集,它支持所有Unicode字符,包括表情符号(emoji)[^3]。
阅读全文
相关推荐



















