2017-10-11 1 views
0

私は複数の列を持つテーブルを持っていますが、そのいくつかはオプションです。私は、各レコードがオプションの列の値を指定しているかどうかにかかわらず、外部ソースからレコードを読み取ります。レコードごとに、指定された値と、指定されていない列の列の既定値を使用して、データベースに行を挿入したいとします。列のデフォルト値をプレースホルダとして指定するにはどうすればよいですか?

すべての列が指定されている場合、私は明らかにちょうど基本的なINSERT文を使用します。一部の値が指定されていない場合

db_cursor.execute("insert into table (col1, col2, col3, col4, col5) " + 
        "values (%s, %s, %s, %s, %s)", 
        (value_1, value_2, value_3, value_4, value_5)) 

しかし、のデフォルトを使用する簡単な方法があるようには思えませんそれらの値のみ。たとえば、SQLのDEFAULTキーワードを使用することができます(または、これらの列をinsert文の外に置くこともできます)。

db_cursor.execute("insert into table (col1, col2, col3, col4, col5) " + 
        "values (%s, %s, %s, DEFAULT, %s)", 
        (value_1, value_2, value_3, value_5)) 

ただし、プレースホルダ値として'DEFAULT'を渡すことはできません。それはちょうどその文字列になるでしょう。

は、これまでのところ私はこの問題への3つのアプローチを考えることができます。

  1. ではなくパラメータを使用するよりも、入力されたデータに基づいて、実行時にSQLクエリ文字列自体を構築します。これは、通常のSQLインジェクションの理由により、非常に強力なアンチパターンです。 (このアプリケーションは実際にはセキュリティ上重大な問題ではありませんが、私のコードにこのようなアンチパターンは必要ありません)。ここで、4つの列がオプションの場合、同じクエリを実行する2^4 = 16の異なるコマンドです。これは明らかに実行不可能です。

  2. デフォルト値をアプリケーションに認識させ、列が指定されていない場合は明示的に送信させます。これにより、デフォルトのSPOTが破棄され、メンテナンスおよび相互運用性に問題があります(複数のアプリケーションがデータベースを読み込みます)。私が考えることができるアプローチのうち、これはおそらく最も悪いことですが、私はまだそれをする必要はありません。

動的に送信されるデフォルトを簡単に管理する方法はありますか?

+0

主な問題は、クエリよりも少ないパラメータを渡すときに、どのようにパラメータを一致させたいのですか? – PRMoureu

+0

クエリにパラメータを渡すより多くのプレースホルダを指定すると、構文エラーが発生すると想定します。理想的なのは、対応するプレースホルダをリテラルではなくDEFAULTにするパラメータ値です。 –

答えて

1

私が通常これを処理する方法は、列リストの代わりにプレースホルダを持ち、文字列format()列のリストを持つことです。列のリストは開発者によって制御され、信頼できないユーザー入力ではないので、これは安全です。

stmt_without_col_names = 'INSERT INTO table ({}) VALUES ({})' 
input_values = [1, None, 1, None, None] 
columns = ('col1', 'col2', 'col3', 'col4', 'col5') 
columns_to_keep = {k: v for k, v in zip(columns, input_values) if v is not None} 
# note: relies on dict key ordering remaining the same 
# this is true if the dict is not modified *at all* between creation 
# and the statement execution - use an OrderedDict or other data 
# structure instead if you're worried 
format_str = ','.join(['%s'] * len(columns_to_keep)) 
stmt = stmt_without_col_names.format(columns_to_keep.keys(), format_str) 
# stmt looks like "INSERT INTO table (['col3', 'col1']) VALUES (%s,%s)" 
cursor.execute(stmt, columns_to_keep.values()) 
関連する問題