sql >> データベース >  >> RDS >> PostgreSQL

PythonリストからPostgreSQL配列へ

    psycopg2では注意してください 配列に対して文字列処理を行う必要はありません。これはエラーが発生しやすく、最悪の場合、インジェクション攻撃を引き起こす可能性があるため、悪い習慣と見なされます。常にバインドされたパラメーターを使用する必要があります。以下のコードでは、タイプがTEXT[]の列が1つだけの新しいテーブルを作成します。 (元の質問のように)。次に、新しい行を追加し、それらすべてを更新します。したがって、両方のINSERTが表示されます およびUPDATE 操作(どちらもほとんど同じですが)

    ただし、cur.executeの1つの値のみで更新する場合は、Pythonの落とし穴が1つあります。 SQLステートメントを最初の引数および反復可能として期待します 2番目の引数としてバインドされるパラメーターを含みます。以下は 仕事:

    from psycopg2 import connect
    
    conn = connect('dbname=exhuma')
    cur = conn.cursor()
    stmt = 'UPDATE foo SET example_value=%s'
    new_values = ['a', 'b', 'c']
    cur.execute(stmt, (new_values))
    conn.commit()
    

    その理由は、(new_values) Pythonではnew_valuesと見なされます (この場合、括弧は削除されます。タプルとは見なされません)。これにより、3つの値('a')を指定するとエラーが発生します。 、'b' および'c' )バインドする値として、ただしプレースホルダーは1つだけです(%s )クエリで。代わりに、次のように指定する必要があります(最後にコンマが追加されていることに注意してください):

    from psycopg2 import connect
    
    conn = connect('dbname=exhuma')
    cur = conn.cursor()
    stmt = 'UPDATE foo SET example_value=%s'
    new_values = ['a', 'b', 'c']
    cur.execute(stmt, (new_values,))
    conn.commit()
    

    これにより、Pythonは(new_values,)を参照できるようになります クエリのプレースホルダーに一致する1つの要素を持つタプル(反復可能)として。末尾のコンマの詳細については、タプルに関する公式ドキュメントを参照してください。

    または、[new_values]と書くこともできます (new_values,)の代わりに 、しかし-私の意見では-(new_values,) タプルは不変であるのに対し、リストは可変であるため、よりクリーンです。

    これが私がテストした表です:

    CREATE TABLE foo (
        values TEXT[]
    );
    

    そして、値の挿入と更新の両方のPythonコードは次のとおりです。

    from psycopg2 import connect
    
    
    conn = connect('dbname=exhuma')
    cur = conn.cursor()
    
    cur.execute('INSERT INTO foo VALUES (%s)', (['a', 'b'], ))
    
    print('>>> Before update')
    cur.execute('SELECT * FROM foo')
    for row in cur:
        print(type(row[0]), repr(row[0]))
    
    print('>>> After update')
    
    cur.execute('UPDATE foo SET example_values = %s',
                (['new', 'updated', 'values'],))
    
    cur.execute('SELECT * FROM foo')
    for row in cur:
        print(type(row[0]), repr(row[0]))
    
    cur.close()
    conn.commit()
    conn.close()
    

    実行のたびに、コードは同じ配列値を持つ新しい行を挿入し、WHEREなしで更新を実行します したがって、すべての値が更新されます。数回実行した後、次の出力が得られます:

    >>> Before update
    (<type 'list'>, "['new', 'updated', 'values']")
    (<type 'list'>, "['new', 'updated', 'values']")
    (<type 'list'>, "['new', 'updated', 'values']")
    (<type 'list'>, "['new', 'updated', 'values']")
    (<type 'list'>, "['new', 'updated', 'values']")
    (<type 'list'>, "['a', 'b']")
    >>> After update
    (<type 'list'>, "['new', 'updated', 'values']")
    (<type 'list'>, "['new', 'updated', 'values']")
    (<type 'list'>, "['new', 'updated', 'values']")
    (<type 'list'>, "['new', 'updated', 'values']")
    (<type 'list'>, "['new', 'updated', 'values']")
    (<type 'list'>, "['new', 'updated', 'values']")
    


    1. 指定されたテーブルの動的な列のセットを返す関数

    2. MicrosoftAccessフォームでドキュメントをプレビューする

    3. リバースエンジニアリング(オラクル)スキーマからERDへ

    4. MySQLで引用符をエスケープするときにバックスラッシュを保持する方法– QUOTE()