source

python MySQLDB IN 절에서 사용할 목록 삽입

factcode 2022. 9. 18. 09:55
반응형

python MySQLDB IN 절에서 사용할 목록 삽입

목록을 문자열에 매핑하는 방법을 알고 있습니다.

foostring = ",".join( map(str, list_of_ids) )

또한 다음 명령을 사용하여 해당 문자열을 IN 절로 가져올 수 있습니다.

cursor.execute("DELETE FROM foo.bar WHERE baz IN ('%s')" % (foostring))

필요한 것은 MySQLDB를 사용하여 안전하게 동일한 작업을 수행하는 것입니다(SQL 주입을 피함). 위의 예에서는 foostring이 실행 인수로 전달되지 않기 때문에 취약합니다.나도 인용을 해야하고 mysql 라이브러리 밖으로 탈출해야 해.

(관련 SO 질문이 있습니다만, 여기에 기재되어 있는 답변은 MySQLDB에서는 동작하지 않거나 SQL 주입에 취약합니다).

를 사용합니다.list_of_ids직접:

format_strings = ','.join(['%s'] * len(list_of_ids))
cursor.execute("DELETE FROM foo.bar WHERE baz IN (%s)" % format_strings,
                tuple(list_of_ids))

이렇게 하면 자신의 견적을 낼 필요가 없어지고 모든 종류의 SQL 주입을 피할 수 있습니다.

데이터(list_of_ids(쿼리 텍스트가 아닌) 파라미터로서 mysql의 드라이버로 직접 이동하기 때문에 주입은 없습니다.문자열에 원하는 문자를 남길 수 있습니다.문자를 삭제하거나 따옴표로 묶을 필요는 없습니다.

이 질문은 꽤 오래된 질문이지만, 만약 내가 원하는 것을 다른 사람이 찾고 있다면 답장을 남기는 것이 좋다고 생각했다.

매개 변수가 많거나 명명된 매개 변수를 사용하려는 경우 수락된 답변이 복잡해집니다.

몇 가지 시험 후

ids = [5, 3, ...]  # list of ids
cursor.execute('''
SELECT 
...
WHERE
  id IN %(ids)s
  AND created_at > %(start_dt)s
''', {
  'ids': tuple(ids), 'start_dt': '2019-10-31 00:00:00'
})

테스트 대상python2.7,pymysql==0.7.11

이는 2021년 Python3에 대한 Rubms의 답변에서 지적된 바와 같이 여전히 문제가 있는 것으로 보인다.

mysql 커넥터 패키지의 "cursor.py" 메서드 "_process_params_params"에 약 9줄의 코드를 추가하면 문제가 해결되었습니다.

def _process_params_dict(self, params):
    """Process query parameters given as dictionary"""
    try:
        to_mysql = self._connection.converter.to_mysql
        escape = self._connection.converter.escape
        quote = self._connection.converter.quote
        res = {}
        for key, value in list(params.items()):
            if type(value) is tuple: ### BEGIN MY ADDITIONS
                res[key.encode()] = b''
                for subvalue in value:
                    conv = subvalue
                    conv = to_mysql(conv)
                    conv = escape(conv)
                    conv = quote(conv)
                    res[key.encode()] = res[key.encode()] + b',' + conv if len(res[key.encode()]) else conv
            else: ### END MY ADDITIONS
                conv = value
                conv = to_mysql(conv)
                conv = escape(conv)
                conv = quote(conv)
                res[key.encode()] = conv
    except Exception as err:
        raise errors.ProgrammingError(
            "Failed processing pyformat-parameters; %s" % err)
    else:
        return res

사용하시는 경우Django 2.0 or 2.1그리고.Python 3.6올바른 방법은 다음과 같습니다.

from django.db import connection
RESULT_COLS = ['col1', 'col2', 'col3']
RESULT_COLS_STR = ', '.join(['a.'+'`'+i+'`' for i in RESULT_COLS])
QUERY_INDEX = RESULT_COLS[0]

TABLE_NAME = 'test'
search_value = ['ab', 'cd', 'ef']  # <-- a list
query = (
    f'SELECT DISTINCT {RESULT_COLS_STR} FROM {TABLE_NAME} a '
    f'WHERE a.`{RESULT_COLS[0]}` IN %s '
    f'ORDER BY a.`{RESULT_COLS[0]}`;'
)  # <- 'SELECT DISTINCT a.`col1`, a.`col2`, a.`col3` FROM test a WHERE a.`col1` IN %s ORDER BY a.`col1`;'
with connection.cursor() as cursor:
    cursor.execute(query, params=[search_value])  # params is a list with a list as its element

참조: https://stackoverflow.com/a/23891759/2803344 https://docs.djangoproject.com/en/2.1/topics/db/sql/ #parameters-into-raw

list_of_ids = [ 1, 2, 3]
query = "select * from table where x in %s" % str(tuple(list_of_ids))
print query

이것은 쿼리 문자열을 완료하기 위해 인수를 전달해야 하는 메서드에 관계되지 않고 단순히 명령어를 호출하고 싶은 경우에 사용할 수 있습니다.cursror.execute(query).

또 다른 방법은 다음과 같습니다.

"select * from table where x in (%s)" % ', '.join(str(id) for id in list_of_ids)

목록 이해를 사용하는 또 다른 간단한 솔루션:

# creating a new list of strings and convert to tuple
sql_list = tuple([ key.encode("UTF-8") for key in list_of_ids ])

# replace "{}" with "('id1','id2',...'idlast')"
cursor.execute("DELETE FROM foo.bar WHERE baz IN {}".format(sql_list))

비록 이 질문은 꽤 오래되었지만.누군가에게 도움이 될 수 있다면 제 해결책을 공유합니다.

list_to_check = ['A', 'B'] cursor.execute("DELETE FROM foo.bar WHERE baz IN ({})".format(str(list_to_check)[1:-1])

테스트 대상Python=3.6

매우 심플: 아래 대형을 사용하십시오.

rules_id = ["9","10"]

sql1 = "SELECT * FROM attendance_schaff WHERE ID in +",+", ".timeout(map(str, rules_id)+""

", ".map(str, rules_id)

언급URL : https://stackoverflow.com/questions/589284/imploding-a-list-for-use-in-a-python-mysqldb-in-clause

반응형