使用 PYODBC 从 pandas 获取数据到 SQL 服务器

Posted

技术标签:

【中文标题】使用 PYODBC 从 pandas 获取数据到 SQL 服务器【英文标题】:Get data from pandas into a SQL server with PYODBC 【发布时间】:2014-10-28 23:35:53 【问题描述】:

我试图了解 python 如何将数据从 FTP 服务器提取到 pandas 中,然后将其移动到 SQL 服务器中。我的代码至少可以说是非常简陋的,我正在寻找任何建议或帮助。我曾尝试先从 FTP 服务器加载数据,但效果很好。...服务器似乎引起了问题。

import pyodbc
import pandas
from ftplib import FTP
from StringIO import StringIO
import csv

ftp = FTP ('ftp.xyz.com','user','pass' )
ftp.set_pasv(True)
r = StringIO()
ftp.retrbinary('filname.csv', r.write)

pandas.read_table (r.getvalue(), delimiter=',')


connStr = ('DRIVER=SQL Server Native Client 10.0;SERVER=localhost;DATABASE=TESTFEED;UID=sa;PWD=pass')
conn = pyodbc.connect(connStr)

cursor = conn.cursor()
cursor.execute("INSERT INTO dbo.tblImport(Startdt, Enddt, x,y,z,)" "VALUES                  (x,x,x,x,x,x,x,x,x,x.x,x)")
cursor.close()
conn.commit()
conn.close()
print"Script has successfully run!"

当我删除 ftp 代码时,它可以完美运行,但我不明白如何进行下一次跳转以将其导入 Microsoft SQL 服务器,或者即使可以不先保存到文件中。

【问题讨论】:

你知道如何将参数传递给execute函数吗?如果是这样,您需要做的就是遍历DataFrame 的行,并为每一行调用execute 并将该行作为SQL 参数的值传递。或者,如果 PyODBC 支持 executemany,那就更简单了——只需传递您已经拥有的任何可迭代的行。 话虽如此,您在这里使用 Pandas 而不是 csv 有什么原因吗?您实际上并没有对数据做任何 Pandas-y 操作,只是对其进行迭代。在这种情况下,csv 要简单得多,并且不需要一次将整个内容全部读入内存。 感谢您的回复,除了我读到它之外,我没有真正使用熊猫,而且转储到数据框似乎是合乎逻辑的。我的基本目标是使用 CSV 将 FTP 数据导入 SQL,这是否只能在事件发生后通过 CVS 文件实现?理想情况下,我想一口气拉入 SQL。 就数据而言,文件非常小(大约 10Kb),因此读入内存不是问题 您不需要创建实际的 CSV 文件; csv 模块与 StringIO 一起工作得很好,就像你已经在做的那样,我很确定 Pandas 也可以。无论哪种方式,目标只是获得一些可迭代的行并通过循环遍历行并调用execute来插入每一行。 【参考方案1】:

以下是使用sqlalchemy 对我有用的方法。注意最后一部分?driver=SQL+Server'

import sqlalchemy
import pyodbc
engine = sqlalchemy.create_engine('mssql+pyodbc://MyUser:MyPWD@dataserver.sandbox.myserver/MY_DB?driver=SQL+Server')
dt.to_sql("PatientResultTest", engine,if_exists='append')

SQL表的开头需要一个index列来存储dataframe的索引值。

【讨论】:

【参考方案2】:

这在 Python 3.5.2 上对我有用:

import sqlalchemy as sa
import urllib
import pyodbc

conn= urllib.parse.quote_plus('DRIVER=ODBC Driver 17 for SQL Server;SERVER='+server+';DATABASE='+database+';UID='+username+';PWD='+ password)
engine = sa.create_engine('mssql+pyodbc:///?odbc_connect='.format(conn))

frame.to_sql("myTable", engine, schema='dbo', if_exists='append', index=False, index_label='myField')

【讨论】:

【参考方案3】:

是的,bcp 实用程序似乎是大多数情况下的最佳解决方案。

如果你想留在 Python 中,下面的代码应该可以工作。

from sqlalchemy import create_engine
import urllib
import pyodbc

quoted = urllib.parse.quote_plus("DRIVER=SQL Server;SERVER=YOUR\ServerName;DATABASE=YOur_Database")
engine = create_engine('mssql+pyodbc:///?odbc_connect='.format(quoted))

df.to_sql('Table_Name', schema='dbo', con = engine, chunksize=200, method='multi', index=False, if_exists='replace')

不要避开method='multi',因为它显着减少了任务执行时间。

有时您可能会遇到以下错误。

ProgrammingError: ('42000', '[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]传入的请求参数太多。这 服务器最多支持 2100 个参数。减少数量 参数并重新发送请求。 (8003) (SQLExecDirectW)')

在这种情况下,请确定数据框中的列数:df.shape[1]。将支持的最大参数数除以该值,并使用结果的下限作为块大小。

【讨论】:

【参考方案4】:

使用 LocalDB SQL 实例的 Python3 版本:

from sqlalchemy import create_engine
import urllib
import pyodbc
import pandas as pd

df = pd.read_csv("./data.csv")

quoted = urllib.parse.quote_plus("DRIVER=SQL Server Native Client 11.0;SERVER=(localDb)\ProjectsV14;DATABASE=database")
engine = create_engine('mssql+pyodbc:///?odbc_connect='.format(quoted))

df.to_sql('TargetTable', schema='dbo', con = engine)

result = engine.execute('SELECT COUNT(*) FROM [dbo].[TargetTable]')
result.fetchall()

【讨论】:

这种将 Python 连接到 MS SQL Server 的方式对我来说是最好的 我必须添加“受信任的连接”值。 "DRIVER=SQL Server Native Client 11.0;SERVER=.;DATABASE=MyDB;Trusted_Connection=yes;"【参考方案5】:

我发现当您拥有大型数据集时,使用 bcp 实用程序 (https://docs.microsoft.com/en-us/sql/tools/bcp-utility) 效果最好。我有 270 万行以 80K 行/秒的速度插入。您可以将数据框存储为 csv 文件(如果您的数据没有制表符和 utf8 编码,则使用制表符作为分隔符)。使用 bcp,我使用了格式“-c”,到目前为止它没有问题。

【讨论】:

bcp 往往会在 csv 文件中引发类型和格式错误。使用像“|”这样的分隔符(从数据中删除)比“,”效果更好。最好将目标表作为所有 varchar 列,这样 bcp 就不会引发错误。然后,您可以通过强制转换来对具有正确类型的目标表运行“插入”。【参考方案6】:

对于“写入 sql server”部分,您可以使用 pandas 方便的 to_sql 方法(因此无需遍历行并手动进行插入)。请参阅有关使用 pandas 与 SQL 数据库进行交互的文档:http://pandas.pydata.org/pandas-docs/stable/io.html#io-sql

您至少需要 pandas 0.14 才能运行此功能,还需要安装 sqlalchemy。举个例子,假设df 是你从read_table 得到的DataFrame:

import sqlalchemy
import pyodbc
engine = sqlalchemy.create_engine("mssql+pyodbc://<username>:<password>@<dsnname>")

# write the DataFrame to a table in the sql database
df.to_sql("table_name", engine)

另请参阅documentation page of to_sql。 更多关于如何使用 sqlalchemy 为带有 pyobdc 的 sql server 创建连接引擎的信息,您可以在这里找到:http://docs.sqlalchemy.org/en/rel_1_1/dialects/mssql.html#dialect-mssql-pyodbc-connect


但如果您的目标只是将 csv 数据导入 SQL 数据库,您也可以考虑直接从 SQL 中执行此操作。参见例如Import CSV file into SQL Server

【讨论】:

感谢您对迟到的回复表示歉意,我会处理这个问题,我相信它会没事的。 我必须传入 engine.raw_connection() 解释这里***.com/questions/20401392/… @RichardBlackman 这对于 pandas 0.14 及更高版本是不正确的。在这种情况下,您应该只传递引擎本身(但是,您链接到的答案与 pandas @joris,请更新答案,链接的文档页面建议从 1.0.0 开始,您需要明确指定驱动程序,create_engine("mssql+pyodbc://scott:tiger@myhost:port/databasename?driver=SQL+Server+Native+Client+10.0") 我试图连接引擎而不指定一个和我的 to_sql一直抱怨我没有选司机 @SomeGuy 感谢您的注意,我更新了 sqlalchemy 文档的链接以链接到较新的版本。

以上是关于使用 PYODBC 从 pandas 获取数据到 SQL 服务器的主要内容,如果未能解决你的问题,请参考以下文章

并行化 pandas pyodbc SQL 数据库调用

PyODBC:/tmp/odbc.log 文件超过 90GB 并停止从数据仓库获取数据

PYODBC 到 Pandas - DataFrame 不起作用 - 传递值的形状是(x,y),索引暗示(w,z)

PYODBC到Pandas - DataFrame不工作 - 传递值的形状是(x,y),索引暗示(w,z)

使用 pyodbc 连接到链接访问数据库

使用 pyODBC 的 fast_executemany 加速 pandas.DataFrame.to_sql