PythonのSQLステートメントで変数を使用する方法


91

わかりましたので、私はPythonの経験がありません。

次のPythonコードがあります。

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

どこvar1の整数であり、var2var3文字列です。

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

回答:


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

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

データベースAPIは、変数の適切なエスケープと引用を行います。文字列フォーマット演算子(%)を使用しないように注意してください。

  1. エスケープや引用は行いません。
  2. SQLインジェクションなど、制御されない文字列形式の攻撃を受けやすい。

興味深いことに、なぜそれは配列(var1、var2、var3)の代わりに個別にvarsで動作するのですか?
Andomar 2009年

DB API仕様によると、それはどちらの方法でもかまいません。python.org
Ayman Hourieh 2009年

9
@thekashyapもう一度注意深く読んでください。安全でないのは、文字列フォーマット演算子を使用していること%です。実際、私は答えでそう言っています。
Ayman Hourieh、2014

私の悪いところ.. 文字列と変数の間にある% 代わりに..を想像しました,..さまざまな理由により、投票を取り消すことができません..個人的には、安全ではない/攻撃などの言葉を、説明の中で言及しているところを見たいと思います使用しない%..
Kashyap

1
@eric答えは文字列をフォーマットするために% 演算子を使用しないことを言います。%文字列内のそれらはcursor.execute直接使用されており、SQLを生成していることがわかっているため、ユーザーを保護するためにより多くのことができます。
Mark Ransom

66

Python DB-APIの異なる実装では、異なるプレースホルダーを使用できます。そのため、使用しているプレースホルダーを確認する必要があります。たとえば、MySQLdbを使用する場合があります。

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

または(たとえば、Python標準ライブラリのsqlite3を使用):

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

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


同じことをすることは可能ですが、外部SQLスクリプトを使用できますか?
Novitoll

46

たくさんの方法。実際のコードでは、最も明白なもの(を使用)を使用しないでください攻撃の可能性があります。%s%

ここで、sqlite3のpydocからコピーして貼り付けます。

# 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))

4
一部のDB-API実装は実際には変数に%sを使用します。特に、PostgreSQLのpsycopg2です。これは、文字列の置換に%sを%演算子と共に使用することと混同しないでください(簡単に混乱します)。移植性のために、DB-APIのSQLパラメータを指定するための定義された標準的な方法を用意できれば、本当にすばらしいと思います。
ThatAintWorking 2014年

24

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

ステートメントに変数の値を単に追加するときは注意してください。ユーザーが自分で名前を付けていると想像してください。';DROP TABLE Users;'それが、SQLエスケープを使用する必要がある理由です。これは、cursor.executeを適切な方法で使用するときにPythonによって提供されます。URLの例は次のとおりです。

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

13
実際には、SQLエスケープではありません。これは可変バインディングであり、はるかに単純で直接的です。値は解析後にSQLステートメントにバインドされるため、注入攻撃の影響を受けません。
S.Lott、2009年

それがSQLエスケープなのか、変数バインディングなのかは、データベースサーバー/ DB-APIドライバーの性能に依存します。データとコードをアウトオブバンドで維持するのではなく、DB-APIドライバーがエスケープするだけの、実際に広く展開されている実稼働データベースをいくつか見ました。言うまでもなく、いわゆる「データベース」にはあまり敬意を払いません。
Charles Duffy
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.