如何在循环中更新SQL Alchemy中的记录

时间:2011-02-05 03:09:58

标签: python sql-server sqlalchemy sqlsoup

我正在尝试使用SQLSoup(SQLAlchemy扩展)来更新SQL Server 2008数据库中的记录。我正在使用pyobdc进行连接。有许多问题使得很难找到相关的例子。

我在一个非常大的表(200万+记录)中重新投影几何字段,因此无法使用许多更新字段的标准方法。我需要从几何字段中提取坐标到文本,转换它们并将它们传回。所有这一切都很好,所有单个部分都在工作。

但是我想在每一行上执行SQL Update语句,同时逐个循环遍历记录。我假设这会锁定记录集,或者连接正在使用 - 就像我使用下面的代码一样,它在成功更新第一条记录后挂起。

有关如何创建新连接,重用现有连接或以其他方式实现此建议的任何建议都表示赞赏。

s = select([text("%s as fid" % id_field),
            text("%s.STAsText() as wkt" % geom_field)],
           from_obj=[feature_table])

rs = s.execute()

for row in rs:
    new_wkt = ReprojectFeature(row.wkt)

    update_value = "geometry :: STGeomFromText('%s',%s)" % (new_wkt, "3785")
    update_sql = ("update %s set GEOM3785 = %s where %s = %i" %
                  (full_name, update_value, id_field, row.fid))

    conn = db.connection()
    conn.execute(update_sql)
    conn.close() #or not - no effect..

现在更新的工作代码如下所示。它在一些记录上工作正常,但挂在整个表上,所以我猜它是在读取太多数据。

db = SqlSoup(conn_string)
#create outer query

Session = sessionmaker(autoflush=False, bind=db.engine)
session = Session()
rs = session.execute(s)

for row in rs: 
    #create update sql...
    session.execute(update_sql)
session.commit()

我现在遇到连接繁忙的错误。

  

DBAPIError :(错误)('HY000','[HY000] [Microsoft] [ODBC SQL Server驱动程序]连接正忙于另一个hstmt(0)的结果(SQLExecDirectW)')

看起来这可能是ODBC驱动程序的问题 - http://sourceitsoftware.blogspot.com/2008/06/connection-is-busy-with-results-for.html

进一步更新

在使用分析器的服务器上,它显示select语句,然后第一个更新语句是“正在启动”但不完整。 如果我将Select语句设置为返回前10行,则它会完成并运行更新。

SQL: Batch Starting   Select...
SQL: Batch Starting   Update...

我认为这是pyodbc和SQL Server驱动程序的问题。如果我删除SQL Alchemy并使用pyodbc执行相同的SQL,它也会挂起。即使我为更新创建了一个新的连接对象。

我还尝试过SQL Server Native Client 10.0驱动程序,它允许使用MARS - Multiple Active Record Sets,但它没有任何区别。最后,我采用了“分页结果”并使用pyodbc和SQL更新这些批次(见下文),但我认为SQLAlchemy能够自动为我做这个。

3 个答案:

答案 0 :(得分:1)

尝试使用Session

rs = s.execute()然后变为session.execute(rs),您可以使用session.execute(update_sql)替换最后三行。我还建议您使用autocommit配置Session,并在结束时调用session.commit()

答案 1 :(得分:1)

我可以建议,当您的进程挂起时,在Sql框中执行sp_who2,看看发生了什么。检查阻塞的spid,看看你是否可以在Sql代码中找到可以提示正在发生的事情的任何内容。如果你发现一个阻止他人的spid,你可以做一个dbcc inputbuffer(*spidid*),看看它是否告诉你它执行了什么查询。否则,您还可以附加Sql探查器并跟踪您的呼叫。

在某些情况下,它也可能是导致阻塞的Sql服务器上的并行性。除非这是一个数据仓库,否则我建议关闭你的Max DOP,(将其设置为1)。让我知道,当我在早上再次检查这件事并且你需要帮助时,我会很乐意提供帮助。

答案 2 :(得分:1)

在找到另一个解决方案之前,我使用单个连接和自定义SQL来返回记录集,并批量更新这些记录。我不认为我在做什么是一个特殊的独特案例,所以我不知道为什么我不能同时处理多个结果集。

下面有效,但非常非常慢......

cnxn = pyodbc.connect(conn_string, autocommit=True)
cursor = cnxn.cursor()

#get total recs in the database
s = "select count(fid) as count from table"
count = cursor.execute(s).fetchone().count

#choose number of records to update in each iteration
batch_size = 100
for i in range(1,count, batch_size):
    #sql to bring back relevant records in each batch
    s = """SELECT fid, wkt from(select ROW_NUMBER() OVER(ORDER BY FID ASC) AS 'RowNumber'
,FID
,GEOM29902.STAsText() as wkt
    FROM %s) features
    where RowNumber >= %i and RowNumber <= %i""" % (full_name,i,i+batch_size)

    rs = cursor.execute(s).fetchall()
    for row in rs:
        new_wkt = ReprojectFeature(row.wkt)
        #...create update sql statement for the record
        cursor.execute(update_sql)
        counter += 1
cursor.close()
cnxn.close()