2012-09-18 50 views
2

我正在編寫一個快速的一次性遷移腳本,該腳本更新一個包含50萬行的表中的單個字段。SQLalchemy 0.7的任何示例,使用from_statement()的UPDATE

因爲我沒有計劃寫出完整的模型,我正在做的初始~25000行數據,我一直在想弄清楚如何使用from_statement做一個UPDATE語句( )調用並使用我自己的原始sql,但我找不到任何示例。

除此之外,SQLalchemy正在拋出一個錯誤。這裏是我的電話和錯誤的例子:

mydb = self.session() 
mydb.query().from_statement(
    """ 
    UPDATE my_table 
    SET settings=mysettings 
    WHERE user_id=myuserid AND setting_id=123 
    """).params(mysettings=new_settings, myuserid=user_id).all() 

的錯誤,我得到:

Traceback (most recent call last): 
    File "./sample_script.py", line 111, in <module> 
    main() 
    File "./sample_script.py", line 108, in main 
    migrate.set_migration_data() 
    File "./sample_script.py", line 100, in set_migration_data 
    """).params(mysettings=new_settings, myuserid=user_id).all() 
    File "/usr/lib/pymodules/python2.6/sqlalchemy/orm/query.py", line 1267, in all 
    return list(self) 
    File "/usr/lib/pymodules/python2.6/sqlalchemy/orm/query.py", line 1361, in __iter__ 
    return self._execute_and_instances(context) 
    File "/usr/lib/pymodules/python2.6/sqlalchemy/orm/query.py", line 1364, in _execute_and_instances 
    result = self.session.execute(querycontext.statement, params=self._params, mapper=self._mapper_zero_or_none()) 
    File "/usr/lib/pymodules/python2.6/sqlalchemy/orm/query.py", line 251, in _mapper_zero_or_none 
    if not getattr(self._entities[0], 'primary_entity', False): 
IndexError: list index out of range 

UPDATE我使用MySQL

每薩米的建議下,我嘗試這樣做:

mydb.execute(
    "UPDATE mytable SET settings=:mysettings WHERE user_id=:userid AND setting_id=123", 
    {'userid': user_id, 'mysettings': new_settings} 
    ) 

這是沒有效果的。我沒有得到任何錯誤,但該聲明似乎並未實際執行,因爲該行不會改變。如果我手動剪切並粘貼從echo = True選項獲取的查詢,該行在數據庫中更新就好了。

更新 - 解決

薩米的建議是正確的,但.execute()調用只適用於 '引擎',而不是 '會議',所以這工作就好了:

self.engine.execute(
    "UPDATE mytable SET settings=:mysettings WHERE user_id=:userid AND setting_id=123", 
    {'userid': user_id, 'mysettings': new_settings} 
    ) 

回答

4

那麼這是相當奇怪的,根據文檔,from_statement用於SELECT陳述。

Execute the given SELECT statement and return results.

我可能在看錯誤的函數,或者可能使用其他類型的語句,我不太確定。

您可以使用execute,因爲它可以執行任何類型的語句,只是一個快速示例。

from sqlalchemy import create_engine 
from sqlalchemy.orm import sessionmaker 

session = sessionmaker(bind = create_engine('sqlite://'), autocommit = True)() 

_ = session.execute('CREATE TABLE my_table (user_id int, setting_id int, settings string)') 
for id in xrange(200): 
    _ = session.execute('INSERT INTO my_table (user_id, setting_id) VALUES (:user_id, :setting_id)', 
     {'user_id':id, 'setting_id':id}) 

_ = session.execute(
""" 
    UPDATE my_table 
    SET settings = :mysettings 
    WHERE user_id = :user_id AND setting_id = 123 
""", {'user_id':123, 'mysettings':'test'}) 

r = session.execute('SELECT * FROM my_table WHERE user_id = :user_id', {'user_id':123}).fetchall() 
print r 

[(123, 123, u'test')] 

注意,這是不是真的用sqlalchemy,其目的是創造一個乾燥的環境中,從一個特定的數據庫後端分離的最佳方法,但你可能有你的理由使用原始的SQL與它的ORM 。

+0

Hi Samy,我也嘗試按照你的建議使用execute()(請參閱我的原始問題中的更新),但它似乎並未實際運行。 – iandouglas

+0

確保你刷新會話,'mydb.flush()' –

+0

我沒有嘗試session.flush,但使用引擎本身執行查詢就好了。再次感謝您的幫助。 – iandouglas

2

你需要使用適當的參數語法;格式完全取決於您的數據庫適配器。例如,一些適配器支持:name PARAMATERS,在這種情況下,你缺少在您的查詢的冒號:

mydb.query().from_statement(
    """ 
    UPDATE my_table 
    SET settings=:mysettings 
    WHERE user_id=:myuserid AND setting_id=123 
    """).params(mysettings=new_settings, myuserid=user_id).all() 

DBAPI 2.0 spec支持多種格式,包括與?%s佔位符位置parametrs,並命名參數在上面的表格並作爲%(name)s格式。您需要查看您的數據庫適配器文檔以瞭解支持的內容。

+0

謝謝Martijn。添加冒號並沒有幫助。我用MySQL標記了我的問題,但應該在我的問題的文本中指定它。我會盡力找到我需要的文檔,但可能只是切換到一個原始的mysql驅動程序,以更快地完成這項工作。 – iandouglas

+0

'mysqldb'使用'%s'參數(位置)。 –

+0

謝謝,也試過了,錯誤消失了,但實際上沒有寫入數據庫。 – iandouglas