Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 带多值插入的ired。如果将来没有提供配置选项,可以通过monkeypatching强制执行旧行为: import pandas.io.sql def insert_statement(self, data, conn): return self.table.insert(), data pandas.io.sql.SQLTable.insert_statement = insert_statement_Python_Sqlalchemy_Pyodbc_Pandas To Sql - Fatal编程技术网

Python 带多值插入的ired。如果将来没有提供配置选项,可以通过monkeypatching强制执行旧行为: import pandas.io.sql def insert_statement(self, data, conn): return self.table.insert(), data pandas.io.sql.SQLTable.insert_statement = insert_statement

Python 带多值插入的ired。如果将来没有提供配置选项,可以通过monkeypatching强制执行旧行为: import pandas.io.sql def insert_statement(self, data, conn): return self.table.insert(), data pandas.io.sql.SQLTable.insert_statement = insert_statement,python,sqlalchemy,pyodbc,pandas-to-sql,Python,Sqlalchemy,Pyodbc,Pandas To Sql,未来就在这里,至少在master分支中,可以使用的关键字参数method=控制插入方法。它默认为None,强制使用executemany方法。传递method='multi'会导致使用多值插入。它甚至可以用于实现特定于DBMS的方法,如@Pylander所指出的PostgresqlCOPY 到目前为止,Turbodbc是数据摄取的最佳选择 我对此非常兴奋,于是在我的github和medium上写了一篇“博客”: 请查收 有关工作示例以及与pandas.to_sql的比较 长话短说 使用turbo

未来就在这里,至少在
master
分支中,可以使用的关键字参数
method=
控制插入方法。它默认为
None
,强制使用executemany方法。传递
method='multi'
会导致使用多值插入。它甚至可以用于实现特定于DBMS的方法,如@Pylander所指出的Postgresql
COPY

到目前为止,Turbodbc是数据摄取的最佳选择

我对此非常兴奋,于是在我的github和medium上写了一篇“博客”: 请查收

有关工作示例以及与pandas.to_sql的比较

长话短说

使用turbodbc 我在3秒内有10000行(77列)

使用pandas.to_sql 我在198秒内得到了相同的10000行(77列)

下面是我正在做的全部细节

进口:

import sqlalchemy
import pandas as pd
import numpy as np
import turbodbc
import time
加载并处理一些数据-用my sample.pkl替换您的:

df = pd.read_pickle('sample.pkl')

df.columns = df.columns.str.strip()  # remove white spaces around column names
df = df.applymap(str.strip) # remove white spaces around values
df = df.replace('', np.nan)  # map nans, to drop NAs rows and columns later
df = df.dropna(how='all', axis=0)  # remove rows containing only NAs
df = df.dropna(how='all', axis=1)  # remove columns containing only NAs
df = df.replace(np.nan, 'NA')  # turbodbc hates null values...
使用sqlAlchemy创建表

不幸的是,turbodbc在创建表和在表上插入数据时需要大量的sql手动劳动和大量的开销

幸运的是,Python是纯粹的乐趣,我们可以自动完成编写sql代码的过程

第一步是创建将接收数据的表。但是,如果您的表包含多个列,则手动创建表并编写sql代码可能会有问题。在我的例子中,表通常有240列

这就是sqlAlchemy和pandas仍然可以帮助我们的地方:pandas不适合编写大量行(在本例中为10000行),但是如果只写6行,即表的开头,又如何呢?通过这种方式,我们可以自动化创建表的过程

创建sqlAlchemy连接:

mydb = 'someDB'

def make_con(db):
    """Connect to a specified db."""
    database_connection = sqlalchemy.create_engine(
        'mssql+pymssql://{0}:{1}@{2}/{3}'.format(
            myuser, mypassword,
            myhost, db
            )
        )
    return database_connection

pd_connection = make_con(mydb)
def turbo_conn(mydb):
    """Connect to a specified db - turbo."""
    database_connection = turbodbc.connect(
                                            driver='ODBC Driver 17 for SQL Server',
                                            server=myhost,
                                            database=mydb,
                                            uid=myuser,
                                            pwd=mypassword
                                        )
    return database_connection
在SQL Server上创建表

使用pandas+sqlAlchemy,但正如前面提到的,只是为turbodbc准备空间。请注意这里的df.head():我们使用pandas+sqlAlchemy只插入6行数据。这将运行得非常快,并且是为了自动创建表而进行的

table = 'testing'
df.head().to_sql(table, con=pd_connection, index=False)
既然桌子已经摆好了,让我们认真点

Turbodbc连接:

mydb = 'someDB'

def make_con(db):
    """Connect to a specified db."""
    database_connection = sqlalchemy.create_engine(
        'mssql+pymssql://{0}:{1}@{2}/{3}'.format(
            myuser, mypassword,
            myhost, db
            )
        )
    return database_connection

pd_connection = make_con(mydb)
def turbo_conn(mydb):
    """Connect to a specified db - turbo."""
    database_connection = turbodbc.connect(
                                            driver='ODBC Driver 17 for SQL Server',
                                            server=myhost,
                                            database=mydb,
                                            uid=myuser,
                                            pwd=mypassword
                                        )
    return database_connection
为turbodbc准备sql命令和数据。让我们以创造性的方式自动创建代码:

def turbo_write(mydb, df, table):
    """Use turbodbc to insert data into sql."""
    start = time.time()
    # preparing columns
    colunas = '('
    colunas += ', '.join(df.columns)
    colunas += ')'

    # preparing value place holders
    val_place_holder = ['?' for col in df.columns]
    sql_val = '('
    sql_val += ', '.join(val_place_holder)
    sql_val += ')'

    # writing sql query for turbodbc
    sql = f"""
    INSERT INTO {mydb}.dbo.{table} {colunas}
    VALUES {sql_val}
    """

    # writing array of values for turbodbc
    valores_df = [df[col].values for col in df.columns]

    # cleans the previous head insert
    with connection.cursor() as cursor:
        cursor.execute(f"delete from {mydb}.dbo.{table}")
        connection.commit()

    # inserts data, for real
    with connection.cursor() as cursor:
        try:
            cursor.executemanycolumns(sql, valores_df)
            connection.commit()
        except Exception:
            connection.rollback()
            print('something went wrong')

    stop = time.time() - start
    return print(f'finished in {stop} seconds')
使用turbodbc写入数据—我在3秒内获得了10000行(77列):

turbo_write(mydb, df.sample(10000), table)
熊猫方法比较-我在198秒内得到了相同的10000行(77列)

table = 'pd_testing'

def pandas_comparisson(df, table):
    """Load data using pandas."""
    start = time.time()
    df.to_sql(table, con=pd_connection, index=False)
    stop = time.time() - start
    return print(f'finished in {stop} seconds')

pandas_comparisson(df.sample(10000), table)
环境和条件

Python 3.6.7 :: Anaconda, Inc.
TURBODBC version ‘3.0.0’
sqlAlchemy version ‘1.2.12’
pandas version ‘0.23.4’
Microsoft SQL Server 2014
user with bulk operations privileges
请检查此代码中的更新

SQL Server插入性能:pyodbc与turbodbc 当使用
to_sql
将pandas数据帧上载到sql Server时,turbodbc在没有
fast\u executemany
的情况下肯定比pyodbc快。但是,对于pyodbc启用了
fast\u executemany
,这两种方法产生的性能基本相同

测试环境:

[venv1_pyodbc]
pyodbc 2.0.25

[venv2_turbodbc]
turbodbc 3.0.0
sqlalchemy turbodbc 0.1.0

[两者通用]
Windows上的Python 3.6.4 64位
SQLAlchemy 1.3.0b1
熊猫0.23.4
numpy 1.15.4

测试代码:

pyodbc的
#
引擎=创建引擎('mssql+pyodbc://sa:whatever@SQL_panorama',fast_executemany=True)
#涡轮增压器
#引擎=创建引擎('mssql+turbodbc://sa:whatever@SQL_全景图')
#测试数据
行数=10000
num_cols=100
df=pd.DataFrame(
[[f'row{x:04}col{y:03}'表示范围内的y(num_cols)]表示范围内的x(num_rows)],
列=[f'col{y:03}表示范围内的y(num_cols)]
)
t0=时间。时间()
df.to_sql(“sqlalchemy_test”,引擎,如果_exists='replace',index=None)
打印(f“在{(time.time()-t0):0.1f}秒内写入{num_rows}行”)
对每个环境运行测试十二(12)次,丢弃每个环境的最佳和最差时间。结果(以秒为单位):

rank pydbc
----  ------  --------
1    22.8      27.5
2    23.4      28.1
3    24.6      28.2
4    25.2      28.5
5    25.7      29.3
6    26.9      29.9
7    27.0      31.4
8    30.1      32.1
9    33.6      32.5
10    39.8      32.9
----  ------  --------
平均27.9 30.0

我遇到了同样的问题,但使用的是PostgreSQL。他们现在刚刚发布了熊猫版本0.24.0,并且在
to_sql
函数中有一个新参数,名为
method
,它解决了我的问题

from sqlalchemy import create_engine

engine = create_engine(your_options)
data_frame.to_sql(table_name, engine, method="multi")
上传速度比我快100倍。
如果要发送大量数据,我还建议设置
chunksize
参数。

只是想添加到@J.K.的答案中

如果您正在使用此方法:

@event.listens_for(engine, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
    if executemany:
        cursor.fast_executemany = True
您将得到以下错误:

“sqlalchemy.exc.DBAPIError:(pyodbc.Error)('HY010','[HY010] [Microsoft][SQL Server本机客户端11.0]函数序列错误(0) (SQLParamData)“[SQL:'插入到…(…)值(?,)'] [参数:(…,…),(…,…)](此错误的背景信息位于: )"

对字符串值进行如下编码:
'yourStringValue'。编码('ascii')


这将解决您的问题。

我只是修改了引擎线路,这有助于将插入速度提高100倍

旧代码-

import json
import maya
import time
import pandas
import pyodbc
import pandas as pd
from sqlalchemy import create_engine

retry_count = 0
retry_flag = True

hostInfoDf = pandas.read_excel('test.xlsx', sheet_name='test')
print("Read Ok")

engine = create_engine("mssql+pyodbc://server_name/db_name?trusted_connection=yes&driver=ODBC+Driver+17+for+SQL+Server")

while retry_flag and retry_count < 5:
  try:
    df.to_sql("table_name",con=engine,if_exists="replace",index=False,chunksize=5000,schema="dbo")
    retry_flag = False
  except:
    retry_count = retry_count + 1
    time.sleep(30)
到-


问我任何与python与SQL连接性相关的查询,我很乐意帮助您。

非常感谢您在这方面做了大量的工作。为了清楚起见,在实例化SQLAlchemy引擎之前应该声明此修饰符和函数?非常欢迎。我在类的构造函数中实例化引擎之后立即声明此修饰符和函数。因此,这就不需要pyodbc特定的连接代码了?只需要在这个函数之后调用
到\u sql()
?我尝试直接在函数之后调用
到\u sql
,但它失败了
Python 3.6.7 :: Anaconda, Inc.
TURBODBC version ‘3.0.0’
sqlAlchemy version ‘1.2.12’
pandas version ‘0.23.4’
Microsoft SQL Server 2014
user with bulk operations privileges
from sqlalchemy import create_engine

engine = create_engine(your_options)
data_frame.to_sql(table_name, engine, method="multi")
@event.listens_for(engine, 'before_cursor_execute')
def receive_before_cursor_execute(conn, cursor, statement, params, context, executemany):
    if executemany:
        cursor.fast_executemany = True
import json
import maya
import time
import pandas
import pyodbc
import pandas as pd
from sqlalchemy import create_engine

retry_count = 0
retry_flag = True

hostInfoDf = pandas.read_excel('test.xlsx', sheet_name='test')
print("Read Ok")

engine = create_engine("mssql+pyodbc://server_name/db_name?trusted_connection=yes&driver=ODBC+Driver+17+for+SQL+Server")

while retry_flag and retry_count < 5:
  try:
    df.to_sql("table_name",con=engine,if_exists="replace",index=False,chunksize=5000,schema="dbo")
    retry_flag = False
  except:
    retry_count = retry_count + 1
    time.sleep(30)
engine = create_engine("mssql+pyodbc://server_name/db_name?trusted_connection=yes&driver=ODBC+Driver+17+for+SQL+Server")
engine = create_engine("mssql+pyodbc://server_name/db_name?trusted_connection=yes&driver=ODBC+Driver+17+for+SQL+Server", fast_executemany=True)