在pyodbc中,将一列更新为另一列

时间:2015-10-19 17:24:22

标签: pyodbc

在SQLServer表中,我想将colB中的值更新为transformColumn(colA),其中transformColumn是一个我不想转换为SQL的python函数。 我尝试了下面的代码,但显然我不能以这种方式同时查询和更新:

Error: ('HY000', '[HY000] [Microsoft][ODBC SQL Server Driver]Connection is busy with results for another hstmt (0) (SQLExecDirectW)')

我如何实现目标?

import pyodbc

def transformColumn(colValue):
    #complicated transformation that I don't want to do in SQL here   

cs = 'DRIVER={SQL Server};Server=mySvr;Database=myDB;Trusted_Connection=Yes;'
cn = pyodbc.connect(cs, autocommit=True)

sqlSelect = """
    SELECT id, colA
    FROM myTable    
"""

sqlUpdate = """
    UPDATE myTable 
    SET colB=? WHERE id=?
"""

csrSelect = cn.cursor()
rows = csrSelect.execute(sqlSelect)
csrUpdate = cn.cursor()

row = csrSelect.fetchone()
while row is not None:
    colB = transformColumn(row.colA)
    csrUpdate.execute(sqlUpdate, colB, row.id)    
    row = csrSelect.fetchone()

csrSelect.close()
csrUpdate.close()
cn.close()

3 个答案:

答案 0 :(得分:2)

如果[colA]上有索引,则以下方法可能是可行的替代方法:

crsr = cnxn.cursor()
crsr.execute("SELECT DISTINCT colA FROM myTable")
aList = [item[0] for item in crsr.fetchall()]
for aValue in aList:
    crsr.execute("UPDATE myTable SET colB=? WHERE colA=?", (transformColumn(aValue), aValue))
crsr.close()
cnxn.commit()

如果[colA]中有重复的值,那将特别有用,因为只计算变换并为每个唯一的[colA]值应用一次

答案 1 :(得分:1)

myTable中的数据是否总是足够小以适应执行此代码的计算机上的内存(例如,总是一个小的查找表,还是会随着时间的推移而继续增长)?

使用Cursor.fetchall()myTable行读入列表,释放光标以用于UPDATE

# starting line 19 in the code sample
csr = cn.cursor()
# this creates a list of pyodbc.Row objects,
# freeing the cursor for update statement execution
rows = csr.execute(sqlSelect).fetchall()
for row in rows:
    colB = transformColumn(row.colA)
    csr.execute(sqlUpdate, colB, row.id)    
cn.commit()

如您所述,为select和update语句使用单独的连接。对于大量数据,这将比上述方法表现更好。它确实需要管理两个连接和游标对象,因为在迭代选择游标时将执行更新。

# starting at line 7 in the code sample
cnSelect = pyodbc.connect(cs, autocommit=True)
cnUpdate = pyodbc.connect(cs, autocommit=True)

sqlSelect = """
    SELECT id, colA
    FROM myTable    
"""

sqlUpdate = """
    UPDATE myTable 
    SET colB=? WHERE id=?
"""

csrSelect = cnSelect.cursor()
csrUpdate = cnUpdate.cursor()
rows = csrSelect.execute(sqlSelect)
for row in rows:
    colB = transformColumn(row.colA)
    csrUpdate.execute(sqlUpdate, colB, row.id)    
cnUpdate.commit()

答案 2 :(得分:-1)

对此的简单解决方案是使用游标,

cnxn = pyodbc.connect("YOUR SERVER DETAILS, CREDENTIALS")
cursor = cnxn.cursor()

query1 = "SELECT * FROM myTable1"
cursor.execute(query1)

query2 = "SELECT * FROM myTable2"
cursor.execute(query2)

这样你在同一个程序中就不需要多个连接了,