【问题标题】:Update on SQL Server table from Python Pandas从 Python Pandas 更新 SQL Server 表
【发布时间】:2020-11-27 20:37:08
【问题描述】:

以下是 python 中的代码,用于更新所需数据库表中的记录。有没有更好的处理方式?

在 SO 中读取,逐行扫描数据帧是一个耗时的过程。有什么更好的处理方法?

for index, row in outputData.iterrows():
    try:
        updatesql = " update table set [fieldname] = {0:f}   where dt = \'{1:s}\'" .format(fieldvalue , currentdt)
        updatecursor.execute(updatesql)
        sql_conn.commit();
except IOError as e:
            print ("({})".format(e))
            pass
        except (RuntimeError, TypeError, NameError) as e:
            print ("({})".format(e))
            pass

根据下面的讨论,做出了改变,但面临两个问题。

 updatesql = " update table set [fieldname] = ? where dt = ?"  
 data = (outputData.reindex( ['fieldvalue'], currentDt,axis='columns').to_numpy())
 # EXECUTE QUERY AND BIND LIST OF TUPLES 
 updatecursor.executemany(updatesql, data.tolist()) 
 sql_conn.commit()

问题 a) 日期是常量,不是 OutputData 数据帧的一部分。 b) 浮点值以科学格式存储。更喜欢以精度存储浮点值。

【问题讨论】:

  • 首先,停止使用模运算符% 进行字符串格式化。这个method has been de-emphasized in Python but not officially deprecated yet。相反,请使用首选的 str.format (Python 2.6+) 或更新的 F-string (Python 3.6+)。 (实际上你应该为这个问题使用 SQL 参数化)。
  • @Parfait,更新了我的代码。谢谢
  • 使用字符串格式将数据插入到 SQL 语句中仍然是一种不鼓励的做法。此外,使用.execute() 逐行遍历DataFrame 的效率低于.executemany()(或my answer 中的等效SQLAlchemy)。
  • @GordThompson,请查看最新声明。我不再循环遍历它。但仍在寻找一种格式化浮点值的方法。

标签: python python-3.x pyodbc


【解决方案1】:

考虑executemany,通过DataFrame.to_numpy() 使用numpy 数组输出来避免for 循环。下面使用 SQL 参数化,而不是任何字符串格式。

With iterrows + cursor.execute (演示参数化)

# PREPARED STATEMENT (NO DATA)
updatesql = "UPDATE SET [fieldname] = ?  WHERE dt = ?"

for index, row in outputData.iterrows():
    try:
        # EXECUTE QUERY AND BIND TUPLE OF PARAMS
        updatecursor.execute(updatesql, (fieldvalue, currentdt))
    except:
        ...

sql_conn.commit()

to_numpy + cursor.executemany

# PREPARED STATEMENT (NO DATA)
updatesql = "UPDATE SET [fieldname] = ?  WHERE dt = ?"

# ROUND TO SCALE OR HOW MANY DECIMAL POINTS OF COLUMN TYPE
outputData['my_field_col'] = outputData['my_field_col'].round(4)

# ADD A NEW COLUMN TO DATA FRAME EQUAL TO CONSTANT VALUE   
outputData['currentDt'] = currentDt
                        
# SUBSET DATA BY NEEDED COLUMNS CONVERT TO NUMPY ARRAY
data = (outputData.reindex(['my_field_col', 'currentDt'], axis='columns').to_numpy())

# EXECUTE QUERY AND BIND LIST OF TUPLES
updatecursor.executemany(updatesql, data.tolist())
sql_conn.commit()

【讨论】:

  • 谢谢。这听起来很有希望。将尝试并返回。
  • 很高兴听到。解决方案有效吗?如果没有,您遇到了什么问题?
  • 如何使用原地替换但格式化浮点值?也就是说,如果我不格式化浮点值,数据库中的各种科学记数法都会更新。
  • 添加了我更新的代码,但它不起作用。告诉我,如何解决。
  • 查看编辑,使用round 匹配列类型的小数点并将日期常量分配为新的数据框列。
【解决方案2】:

这是您可以使用 pyodbc 的 fast_executemany=True 的另一种方法:

import sqlalchemy as sa

# …

print(outputData)  # DataFrame containing updates
"""console output:
   my_field_col my_date_col
0             0  1940-01-01
1             1  1941-01-01
2             2  1942-01-01
…
"""

engine = sa.create_engine(connection_uri, fast_executemany=True)

update_stmt = sa.text(
    f"UPDATE [{table_name}] SET [fieldname] = :my_field_col WHERE dt = :my_date_col"
)
update_data = outputData.to_dict(orient="records")
with engine.begin() as conn:
    conn.execute(update_stmt, update_data)

【讨论】:

    猜你喜欢
    • 2012-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-12
    • 1970-01-01
    相关资源
    最近更新 更多