Python MySQL IN 절에 사용할 목록을 압축하는 중
목록을 문자열에 매핑하는 방법을 알고 있습니다.
foostring = ",".join( map(str, list_of_ids) )
그리고 다음을 사용하여 문자열을 IN 절에 넣을 수 있습니다.
cursor.execute("DELETE FROM foo.bar WHERE baz IN ('%s')" % (foostring))
제가 필요한 것은 MySQL 데이터베이스를 사용하여 동일한 작업을 안전하게 수행(SQL 주입 회피)하는 것입니다.footstring이 실행할 인수로 전달되지 않기 때문에 위의 예제에서는 취약합니다.또한 인용하고 MySQL 라이브러리 외부로 탈출해야 합니다.
(관련 SO 질문이 있지만 여기에 나열된 답변은 MySQL 데이터베이스에서 작동하지 않거나 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
마크의 답변에 대한 Rubms의 논평에서 지적했듯이 이것은 2021년 Python3에 여전히 문제가 있는 것으로 보입니다.
튜플을 처리하기 위해 mysql 커넥터 패키지의 "cursor.py "에 있는 메서드 "_process_params_module"에 약 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
질문에 조금 늦었을 수도 있지만, 비슷한 문제를 우연히 발견했지만, 이름이 지정된 매개 변수의 딕트를 튜플 대신 사용하고 싶었습니다(일부 매개 변수를 추가하거나 제거하기 위해 매개 변수를 수정하려는 경우 튜플을 다시 구성하고 싶지 않기 때문에 순서를 엉망으로 만드는 것은 매우 쉽고 버그를 유발할 수 있습니다...).
제 솔루션은 쿼리 문자열을 포맷하여 매개 변수를 여러 매개 변수로 분해한 다음 다음 새 매개 변수로 dict 매개 변수를 구성하는 것이었습니다.
from typing import Iterable
query = """
SELECT *
FROM table
WHERE id IN (%(test_param)s)
"""
parameters = {"test_param": [1, 2, 3])
new_params = {}
for k, v in parameters.items():
if isinstance(v, Iterable):
iterable_params = {f"{k}_{i}": value for i, value in enumerate(v)}
iterable_params_formatted = [f"%({k}_{i})s" for i in range(0, len(v))]
query = query.replace(f"%({k})s", ", ".join(iterable_params_formatted))
new_params.update(iterable_params)
else:
new_params[k] = v
print(query)
print(new_params)
결과:
> SELECT *
FROM table
WHERE id IN (%(test_param_0)s, %(test_param_1)s, %(test_param_2)s)
> {'test_param_0': 1, 'test_param_1': 2, 'test_param_2': 3}
더 잘 할 수 있지만, 주문된 튜플 대신 명명된 매개 변수의 딕트를 사용하여 해결책을 찾을 수 없습니다.
사용하는 경우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
ref: https://stackoverflow.com/a/23891759/2803344 https://docs.djangoproject.com/en/2.1/topics/db/sql/ #모수 매개 변수를 원시로 변환
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_map_staff WHERE id in ("+, ".sql(map(str, rules_id)+""
.map(map(str, rules_id))
언급URL : https://stackoverflow.com/questions/589284/imploding-a-list-for-use-in-a-python-mysql-in-clause
'programing' 카테고리의 다른 글
MariaDB/InnoDB에서 ADD COLUMON AFTER를 실행할 때 위험이 있습니까? (0) | 2023.08.19 |
---|---|
애플리케이션 풀 ID를 사용하는 IIS 애플리케이션에서 기본 토큰을 손실하시겠습니까? (0) | 2023.08.19 |
ProgressDialog는 더 이상 사용되지 않습니다.대체 사용할 수 있는 것은 무엇입니까? (0) | 2023.08.19 |
라라벨: 어디에 있는지 순서 (0) | 2023.08.19 |
Oracle plsql 블록에서 한 줄로 여러 변수를 선언하는 방법 (0) | 2023.08.19 |