3

50 万行のテーブルの 1 つのフィールドを更新する、1 回限りの簡単な移行スクリプトを作成しています。

最初の ~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

アップデート

私はMySQLを使用しています。

サミーの提案に従って、私はこれを試しました:

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

これは効果がありませんでした。エラーは発生しませんが、行が変更されないため、ステートメントは実際には実行されていないようです。echo=True オプションからログに記録されたクエリを手動でカット アンド ペーストすると、データベース内の行が正常に更新されます。

更新 - 解決済み

Samy の提案は正しかったのですが、.execute() 呼び出しは「セッション」ではなく「エンジン」でのみ機能するため、これはうまく機能しました。

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

2 に答える 2

4

ドキュメントによると、これはかなり奇妙です。 from_statementSELECTステートメントに使用されます。

指定された SELECT ステートメントを実行し、結果を返します。

間違った関数を見ている可能性があります。または、他のタイプのステートメントを使用できる可能性がありますが、よくわかりません。

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これは、特定の db バックエンドから切り離されたドライ環境を作成するように設計されたを使用するための最良の方法ではないことに注意してください。

于 2012-09-18T20:52:07.410 に答える
3

適切なパラメーター構文を使用する必要があります。形式はデータベース アダプタに完全に依存します。たとえば、一部のアダプターは:nameパラメーターをサポートしていますが、その場合、クエリにこれらのコロンがありません。

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 仕様?では、%sプレースホルダーを使用した位置パラメーター、上記の形式および%(name)s書式設定としての名前付きパラメーターなど、いくつかの形式がサポートされています。サポートされているものを確認するには、データベース アダプタのドキュメントを確認する必要があります。

于 2012-09-18T19:52:29.797 に答える