Mysql 如何在pd.read\u SQL\u查询中一次执行多个SQL命令?
让我创建一个要讨论的用例Mysql 如何在pd.read\u SQL\u查询中一次执行多个SQL命令?,mysql,python-3.x,sqlalchemy,pymysql,Mysql,Python 3.x,Sqlalchemy,Pymysql,让我创建一个要讨论的用例 CREATE DATABASE sample; USE sample; CREATE TABLE quote ( `id` int(2) unsigned NOT NULL AUTO_INCREMENT, `code` text , `date` date DEFAULT NULL, `close` double DEFAULT NULL, PRIMARY KEY (`id`) ) ; INSERT INTO quote (`code`, `da
CREATE DATABASE sample;
USE sample;
CREATE TABLE quote (
`id` int(2) unsigned NOT NULL AUTO_INCREMENT,
`code` text ,
`date` date DEFAULT NULL,
`close` double DEFAULT NULL,
PRIMARY KEY (`id`)
) ;
INSERT INTO quote (`code`, `date`, `close`)
VALUES ('epm', '20200824', 2.64);
INSERT INTO quote (`code`, `date`, `close`)
VALUES ('dss', '20200824', 6.4);
使用sqlalchemy只执行一个sql命令很简单
import pandas as pd
from sqlalchemy import create_engine
user = 'root'
mysql_pass = 'your mysql passwd'
mysql_ip = '127.0.0.1'
engine = create_engine("mysql+pymysql://{}:{}@{}:3306".format(user,mysql_pass,mysql_ip))
cmd_one_line_sql = 'select * from sample.quote;'
df = pd.read_sql_query(cmd_one_line_sql,con = engine)
df
id code date close
0 1 epm 2020-08-24 2.64
1 2 dss 2020-08-24 6.40
我得到了期望的结果,现在cmd包含多个sql命令,为了简单起见,它只包含两行
cmd_multi_lines_sql = 'use sample;select * from quote;'
cmd\u multi\u line\u sql
只是将cmd\u one\u line\u sql
拆分为两个。我根据手册重写了代码片段:
获取以下错误信息:
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
File "/usr/local/lib/python3.5/dist-packages/pymysql/cursors.py", line 170, in execute
result = self._query(query)
File "/usr/local/lib/python3.5/dist-packages/pymysql/cursors.py", line 328, in _query
conn.query(q)
File "/usr/local/lib/python3.5/dist-packages/pymysql/connections.py", line 517, in query
self._affected_rows = self._read_query_result(unbuffered=unbuffered)
File "/usr/local/lib/python3.5/dist-packages/pymysql/connections.py", line 732, in _read_query_result
result.read()
File "/usr/local/lib/python3.5/dist-packages/pymysql/connections.py", line 1075, in read
first_packet = self.connection._read_packet()
File "/usr/local/lib/python3.5/dist-packages/pymysql/connections.py", line 684, in _read_packet
packet.check_error()
File "/usr/local/lib/python3.5/dist-packages/pymysql/protocol.py", line 220, in check_error
err.raise_mysql_exception(self._data)
File "/usr/local/lib/python3.5/dist-packages/pymysql/err.py", line 109, in raise_mysql_exception
raise errorclass(errno, errval)
pymysql.err.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'select * from quote' at line 1")
它输出相同的错误信息。如何修复它?您面临的问题是:
MULTI_语句
标志传递给PyMySQL,然后read\u sql\u query
假定第一个结果集包含数据帧的数据,而对于匿名代码块,这可能不是真的将熊猫作为pd导入
导入pymysql
从pymysql.constants导入客户端
连接信息={
“主机”:“本地主机”,
“港口”:3307,
“用户”:“根用户”,
“密码”:“嘟嘟”,
“数据库”:“mydb”,
“client_标志”:client.MULTI_语句,
}
cnxn=pymysql.connect(**连接信息)
crsr=cnxn.cursor()
sql=”“”\
创建临时表tmp(id int主键,txt varchar(20))
ENGINE=InnoDB默认字符集=utf8mb4 COLLATE=utf8mb4\u unicode\u ci;
在tmp(id,txt)值中插入(1,'foo'),(2,'crmk∏Α!');
从tmp中选择id、txt;
"""
crsr.execute(sql)
尝试次数=5
结果=无
对于范围内的i(尝试次数):
结果=crsr.fetchall()
如果结果为:
打破
crsr.nextset()
如果没有结果:
打印(f)(在{num_尝试}次尝试后未找到结果)
其他:
df=pd.DataFrame(结果,列=[x[0]表示crsr.description中的x])
打印(df)
“”“控制台输出:
id文本
0 1 foo
1 2 ΟΠΑ!
"""
(编辑)其他注释:
注1:如中所述,您可以使用SQLAlchemy的create\u engine
方法的connect\u args
参数传递MULTI\u语句
标志。如果您需要一个SQLAlchemy引擎
对象来处理其他事情(例如,to_sql
),那么这可能比直接创建自己的PyMySQL连接更好
注2:
num\u tries
可以任意大;这只是一种避免无止境循环的方法。如果我们需要跳过前n个空结果集,那么我们需要多次调用nextset
,一旦我们找到了非空结果集,我们就打破循环。经过soem研究并在github询问
答案显而易见
您需要使用传递所需的参数
connect_args=
以及自sqlalchemy以来的参数
是
所以你的python代码和他的很像
from sqlalchemy import create_engine
import pymysql
from pymysql.constants.CLIENT import MULTI_STATEMENTS
user = 'root'
mysql_pass = 'testpassword'
mysql_ip = 'localhost'
cmd = 'SELECT * FROM table1;SELECT * FROM test'
engine = create_engine("mysql+pymysql://{}:{}@{}:3306/testdb1?charset=utf8".format(user,mysql_pass,mysql_ip),connect_args={"client_flag": MULTI_STATEMENTS})
connection = engine.raw_connection()
try:
cursor = connection.cursor()
cursor.execute(cmd)
results_one = cursor.fetchall()
cursor.nextset()
results_two = cursor.fetchall()
cursor.close()
finally:
connection.close()
但使用此解决方案,您需要事先知道运行哪些查询
如果您想更加灵活,使用动态sql语句
from sqlalchemy import create_engine
user = 'root'
mysql_pass = 'testpassword'
mysql_ip = 'localhost'
cmd = 'SELECT * FROM table1;SELECT * FROM test'
engine = create_engine("mysql+pymysql://{}:{}@{}:3306/testdb1?charset=utf8".format(user,mysql_pass,mysql_ip))
connection = engine.raw_connection()
splitstring = cmd.split(";")
ges_resultset = []
try:
cursor = connection.cursor()
for cmdoneonly in splitstring:
cursor.execute(cmdoneonly)
results = cursor.fetchall()
ges_resultset.append(results)
cursor.close()
finally:
connection.close()
在这里,您可以检查每个命令,并了解python如何对其作出反应
- 选择需要获取结果集
- 插入删除创建您不需要的内容(还有更多内容,但您可以了解要点)
@Gord Thompson,我对自动设置num_尝试进行了一些改进:
import pandas as pd
import pymysql
from pymysql.constants import CLIENT
conn_info = {
"host": "localhost",
"port": 3306,
"user": "root",
"password": "your mysql passwd",
"client_flag": CLIENT.MULTI_STATEMENTS,
}
cnxn = pymysql.connect(**conn_info)
crsr = cnxn.cursor()
sql = """\
create database sample;
USE sample;
CREATE TEMPORARY TABLE tmp (id int primary key, txt varchar(20))
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO tmp (id, txt) VALUES (1, 'foo'), (2, 'ΟΠΑ!');
SELECT id, txt FROM tmp;
SELECT txt FROM tmp;
"""
crsr.execute(sql)
num_tries = sql.count(';') if sql.endswith(';') else sql.count(';') + 1
for i in range(num_tries):
result = crsr.fetchall()
if result:
df = pd.DataFrame(result, columns=[x[0] for x in crsr.description])
print(df)
crsr.nextset()
@nbk:当cmd
包含许多sql语句时,执行代码可能会遇到以下问题:
pymysql.err.InternalError: (1065, 'Query was empty')
根据您的代码进行一些改进:
import pandas as pd
from sqlalchemy import create_engine
user = 'root'
mysql_pass = 'your mysql passwd'
mysql_ip = 'localhost'
sql = """\
create database sample;
USE sample;
CREATE TEMPORARY TABLE tmp (id int primary key, txt varchar(20))
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO tmp (id, txt) VALUES (1, 'foo'), (2, 'ΟΠΑ!');
SELECT id, txt FROM tmp;
SELECT txt FROM tmp;
"""
engine = create_engine("mysql+pymysql://{}:{}@{}:3306".format(user,mysql_pass,mysql_ip))
connection = engine.raw_connection()
splitstring = sql.split(";")
try:
cursor = connection.cursor()
for cmdoneonly in splitstring:
if cmdoneonly.strip():
cursor.execute(cmdoneonly)
results = cursor.fetchall()
if results :
df = pd.DataFrame(results, columns=[x[0] for x in cursor.description])
print(df)
cursor.close()
finally:
connection.close()
- 如果cmdoneonly.strip():
为避免1065:查询为空
错误,则需要添加一个determine语句
这是一个很棒的语句df=pd.DataFrame(结果,cursor.description中x的列=[x[0])
学习@Gord Thompson
如果未编辑收到的错误消息,则cmd变量(或文本文件)显然包含“cmd commands here”字符串。如果您编辑了它,在不知道sql错误是什么的情况下很难帮助您。太棒了df=pd.DataFrame(结果,列=[x[0]表示crsr.description中的x])
,卓越!希望SQLAlchemy上的开发人员升级以支持MULTI_语句的sql。我如何才能向您发送250声誉奖金?@showkey-我很感激您的想法,但不用担心。很高兴您找到了一个令人满意的解决方案。请参阅re:在分号字符上拆分匿名代码块。这是一个关于mysql和pymysql的问题,正如预期的那样,对于SQL server,我根本找不到任何支持SQL server多查询的解决方案。但请随意告知,默认情况下,meSQL服务器支持匿名代码块(至少在我遇到的任何情况下),因此无需显式启用“多个语句”。该启用特定于py、ysql,并且因驱动程序而异。我怀疑我们是否可以制作一个通用的特别代码,但这将是一个离题的话题。我如何才能向您发送250个声誉奖金?请注意,一些SQL方言(例如T-SQL)可能会非常宽松地要求语句以分号结尾,因此简单地将文本拆分为计数语句并不总是有效的。
import pandas as pd
import pymysql
from pymysql.constants import CLIENT
conn_info = {
"host": "localhost",
"port": 3306,
"user": "root",
"password": "your mysql passwd",
"client_flag": CLIENT.MULTI_STATEMENTS,
}
cnxn = pymysql.connect(**conn_info)
crsr = cnxn.cursor()
sql = """\
create database sample;
USE sample;
CREATE TEMPORARY TABLE tmp (id int primary key, txt varchar(20))
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO tmp (id, txt) VALUES (1, 'foo'), (2, 'ΟΠΑ!');
SELECT id, txt FROM tmp;
SELECT txt FROM tmp;
"""
crsr.execute(sql)
num_tries = sql.count(';') if sql.endswith(';') else sql.count(';') + 1
for i in range(num_tries):
result = crsr.fetchall()
if result:
df = pd.DataFrame(result, columns=[x[0] for x in crsr.description])
print(df)
crsr.nextset()
pymysql.err.InternalError: (1065, 'Query was empty')
import pandas as pd
from sqlalchemy import create_engine
user = 'root'
mysql_pass = 'your mysql passwd'
mysql_ip = 'localhost'
sql = """\
create database sample;
USE sample;
CREATE TEMPORARY TABLE tmp (id int primary key, txt varchar(20))
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO tmp (id, txt) VALUES (1, 'foo'), (2, 'ΟΠΑ!');
SELECT id, txt FROM tmp;
SELECT txt FROM tmp;
"""
engine = create_engine("mysql+pymysql://{}:{}@{}:3306".format(user,mysql_pass,mysql_ip))
connection = engine.raw_connection()
splitstring = sql.split(";")
try:
cursor = connection.cursor()
for cmdoneonly in splitstring:
if cmdoneonly.strip():
cursor.execute(cmdoneonly)
results = cursor.fetchall()
if results :
df = pd.DataFrame(results, columns=[x[0] for x in cursor.description])
print(df)
cursor.close()
finally:
connection.close()