2009-05-23 21 views
49

私はPythonでそれほど経験はありません。PythonのSQL文で変数を使用する方法は?

私は次のPythonコードを持っている:var1は整数

cursor.execute("INSERT INTO table VALUES var1, var2, var3,") 

を、var2 & var3は文字列です。

Pythonを使用せずに変数名をクエリテキストの一部として書き込むにはどうすればよいですか?

答えて

57
cursor.execute("INSERT INTO table VALUES (%s, %s, %s)", (var1, var2, var3)) 

パラメータはタプルとして渡されることに注意してください。

データベースAPIは、適切なエスケープと変数の引用を行いません。それはどんなエスケープや引用を行いません

  1. ので、オペレータのフォーマット文字列(%)を使用しないように注意してください。
  2. 制御されていない文字列形式の攻撃を受けやすい。 SQL injection
+0

興味深い、それはVARSで別々の代わりに、配列で仕事ない理由(var1、var2、var3)? – Andomar

+0

DB APIの仕様によれば、どちらの方法でも可能です:http://www.python.org/dev/peps/pep-0249/ –

+0

http://docs.python.org/2/library/ sqlite3.html#エスケープ – earthmeLon

16

http://www.amk.ca/python/writing/DB-API.html

あなたは、単にあなたの文に変数の値を追加するときには注意してください: 自身';DROP TABLE Users;'命名ユーザー想像して - ときはPythonがあなたのために提供され、あなたはSQLのエスケープを使用する必要がある理由です をまともな方法でcursor.executeを使用してください。 URLでの例は次のとおりです。あなたが使用しているどちら見つける必要がありますので、PythonのDB-APIの

cursor.execute("insert into Attendees values (?, ?, ?)", (name, 
seminar, paid)) 
+7

実際には、SQLはエスケープしていません。これは可変バインディングであり、はるかに簡単で直接的です。値は解析後にSQLステートメントにバインドされ、あらゆる注入攻撃から免除されます。 –

+0

"リトルボビーテーブル、我々は彼を呼び出します。"あなたの入力をサニタイズする。 https://xkcd.com/327/ – mattmc3

40

異なる実装は、異なるプレースホルダを使用することを許可されている - それは、例えばと(かもしれませんMySQLdbは):Pythonの標準ライブラリからsqlite3のと

cursor.execute("INSERT INTO table VALUES (%s, %s, %s)", (var1, var2, var3)) 

か(例):

cursor.execute("INSERT INTO table VALUES (?, ?, ?)", (var1, var2, var3)) 

や他の人はまだ(VALUES後にあなたが(:1, :2, :3)を持つことができ、または"名前付きスタイル" (:fee, :fie, :fo)または(%(fee)s, %(fie)s, %(fo)s)ここでは、executeの2番目の引数としてマップの代わりにdictを渡します。使用しているDB APIモジュールの文字列定数paramstyleを確認し、パラメータタイプがすべてであるかどうかを調べるには、http://www.python.org/dev/peps/pep-0249/のparamstyleを探してください。

+0

外部SQLスクリプトでも同じことが可能ですか? – Novitoll

19

さまざまな方法があります。 は、最も明白なもの(%s%)を実際のコードで使用しないでください。attacksに公開されています。

はここでコピーpaste'd from pydoc of sqlite3:あなたが必要な場合は

# Never do this -- insecure! 
symbol = 'RHAT' 
c.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol) 

# Do this instead 
t = ('RHAT',) 
c.execute('SELECT * FROM stocks WHERE symbol=?', t) 
print c.fetchone() 

# Larger example that inserts many records at a time 
purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00), 
      ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00), 
      ('2006-04-06', 'SELL', 'IBM', 500, 53.00), 
      ] 
c.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases) 

より多くの例:

# Multiple values single statement/execution 
c.execute('SELECT * FROM stocks WHERE symbol=? OR symbol=?', ('RHAT', 'MSO')) 
print c.fetchall() 
c.execute('SELECT * FROM stocks WHERE symbol IN (?, ?)', ('RHAT', 'MSO')) 
print c.fetchall() 
# This also works, though ones above are better as a habit as it's inline with syntax of executemany().. but your choice. 
c.execute('SELECT * FROM stocks WHERE symbol=? OR symbol=?', 'RHAT', 'MSO') 
print c.fetchall() 
# Insert a single item 
c.execute('INSERT INTO stocks VALUES (?,?,?,?,?)', ('2006-03-28', 'BUY', 'IBM', 1000, 45.00)) 
+0

DB-APIの実装の中には、実際には変数に%sを使用しています。特に、PostgreSQLの場合はpsycopg2です。これは%sを文字列置換のための%演算子とともに使用すると混乱することはありません(簡単ですが)。 移植性のために、DB-APIのSQLパラメータを指定するための標準的な定義方法があればいいと思います。 – ThatAintWorking

関連する問題