Python 插入到可变列数时正确设置SQL查询的格式

Python 插入到可变列数时正确设置SQL查询的格式,python,sql,python-3.x,postgresql,psycopg2,Python,Sql,Python 3.x,Postgresql,Psycopg2,我正在使用psycopg2与PostgreSQL数据库交互。我有一个函数,可以将表中任意数量的列(从单个列到所有列)插入到。我的问题是:如何正确地、动态地构造这个查询 目前我正在使用字符串格式和连接,我知道这是绝对最糟糕的方法。考虑下面的代码,在这种情况下,我未知的列数(即,从 DICT中的键实际上是2): query=INSERT-INTO-myTable(key1,key2)值(3,'myString')返回someValue 这提供了一个格式正确的查询,但当然容易出现SQL注入之类的情况,

我正在使用
psycopg2
PostgreSQL
数据库交互。我有一个函数,可以将表中任意数量的列(从单个列到所有列)插入到。我的问题是:如何正确地、动态地构造这个查询

目前我正在使用字符串格式和连接,我知道这是绝对最糟糕的方法。考虑下面的代码,在这种情况下,我未知的列数(即,从<代码> DICT</代码>中的键实际上是2):

query=INSERT-INTO-myTable(key1,key2)值(3,'myString')返回someValue

这提供了一个格式正确的查询,但当然容易出现SQL注入之类的情况,因此,实现我的目标不是一种可接受的方法

在其他查询中,我在处理已知数量的变量(
%s
和包含变量的
.execute()
的单独参数)时使用查询构造方法,但我不确定如何在不使用字符串格式的情况下调整此方法以适应未知数量的变量


如何优雅而安全地构造具有未知数量的指定插入列的查询?

更令人担忧的是,当前使用
.replace()
的方法很容易出现字段或值包含
[
]
'
的边缘情况。无论发生什么,它们都会被替换,并且可能会打乱您的查询

您可以始终使用
.join()
在列表中加入数量可变的值。要加满它,请在
值之后适当地使用
%s
查询,并将参数传递到
.execute()

<>注释:您也可以考虑字段的数目不等于数字值的情况。


我相信这种方法会导致列名被视为字符串,从而封装在
'
中,因此是无效的SQL语法?请确保
len(字段)==len(值)
是一个非常好的观点,谢谢。
dictOfUnknownLength = {'key1': 3, 'key2': 'myString'}

def createMyQuery(user_ids, dictOfUnknownLength):
    fields, values = list(), list()

    for key, val in dictOfUnknownLength.items():
        fields.append(key)
        values.append(val)

    fields = str(fields).replace('[', '(').replace(']', ')').replace("'", "")
    values = str(values).replace('[', '(').replace(']', ')')

    query = f"INSERT INTO myTable {fields} VALUES {values} RETURNING someValue;"
import psycopg2


conn = psycopg2.connect("dbname=test user=postgres")
cur = conn.cursor()

dictOfUnknownLength = {'key1': 3, 'key2': 'myString'}


def createMyQuery(user_ids, dictOfUnknownLength):
    # Directly assign keys/values.
    fields, values = list(dictOfUnknownLength.keys()), list(dictOfUnknownLength.values())

    if len(fields) != len(values):
        # Raise an error? SQL won't work in this case anyways...
        pass

    # Stringify the fields and values.
    fieldsParam = ','.join(fields) # "key1, key2"
    valuesParam = ','.join(['%s']*len(values))) # "%s, %s"

    # "INSERT ... (key1, key2) VALUES (%s, %s) ..."
    query = 'INSERT INTO myTable ({}) VALUES ({}) RETURNING someValue;'.format(fieldsParam, valuesParam)

    # .execute('INSERT ... (key1, key2) VALUES (%s, %s) ...', [3, 'myString'])
    cur.execute(query, values) # Anti-SQL-injection: pass placeholder
                               # values as second argument.