Wiem, jak zmapować listę na ciąg:
foostring = ",".join( map(str, list_of_ids) )
Wiem, że mogę użyć następującego ciągu, aby umieścić ten ciąg w klauzuli IN:
cursor.execute("DELETE FROM foo.bar WHERE baz IN ('%s')" % (foostring))
To, czego potrzebuję, to zrobić to samo BEZPIECZNIE (unikając wstrzykiwania SQL) za pomocą MySQLDB. W powyższym przykładzie, ponieważ foostring nie jest przekazywany jako argument do wykonania, jest podatny na ataki. Muszę też cytować i uciec poza bibliotekę mysql.
(Istnieje powiązane pytanie SO , ale wymienione tam odpowiedzi albo nie działają w przypadku MySQLDB, albo są podatne na wstrzyknięcie SQL).
Odpowiedzi:
Użyj
list_of_ids
bezpośrednio:format_strings = ','.join(['%s'] * len(list_of_ids)) cursor.execute("DELETE FROM foo.bar WHERE baz IN (%s)" % format_strings, tuple(list_of_ids))
W ten sposób unikniesz konieczności cytowania siebie i wszelkiego rodzaju iniekcji sql.
Zauważ, że data (
list_of_ids
) trafia bezpośrednio do sterownika mysql jako parametr (nie w tekście zapytania), więc nie ma iniekcji. Możesz zostawić dowolne znaki w ciągu znaków, bez potrzeby usuwania lub cytowania znaków.źródło
?
nie jest,%s
więc zadziała, jeśli zmienisz pierwszą linię naformat_strings = ','.join('?' * len(list_of_ids))
.% format_strings
część zmieniała inne%s
symbole zastępcze w zapytaniu, tylkoIN (%s)
symbol zastępczy - sposobem na to jest podwojenie wszystkich%
znaków oprócz tego, który chcesz zastąpić:query = ("select distinct cln from vcf_commits where branch like %%s and repository like %%s and filename in (%s) and author not like %%s" % format_strings,); cursor.execute(query, (branch, repository) + tuple(fname_list) + (invalid_author,))
Chociaż to pytanie jest dość stare, pomyślałem, że lepiej zostawić odpowiedź na wypadek, gdyby ktoś szukał tego, czego szukałem
Zaakceptowana odpowiedź staje się nieczytelna, gdy mamy dużo parametrów lub gdy chcemy używać nazwanych parametrów
Po kilku próbach
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' })
Testowane
python2.7
,pymysql==0.7.11
źródło
Jeśli używasz
Django 2.0 or 2.1
iPython 3.6
, to jest właściwy sposób: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/#passing-parameters-into-raw
źródło
Chociaż to pytanie jest dość stare. Dzielę się moim rozwiązaniem, jeśli może to komuś pomóc.
list_to_check = ['A', 'B'] cursor.execute("DELETE FROM foo.bar WHERE baz IN ({})".format(str(list_to_check)[1:-1])
Testowane z
Python=3.6
źródło
list_to_check
nie jest zabezpieczone przed ucieczką SQL. Dlategoexecute
właściwsze jest przekazywanie wartości jako parametrów do . Korzystaj z tego rozwiązania bardzo ostrożnie (tzn. Identyfikatory wejściowe nie są odbierane jako parametry z zewnątrz aplikacji), ponieważ ktoś mógłby użyć tego rozwiązania do zaatakowania systemu i uzyskania dostępu do bazy danych.Kolejne proste rozwiązanie wykorzystujące rozumienie list:
# 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))
źródło
list_of_ids = [ 1, 2, 3] query = "select * from table where x in %s" % str(tuple(list_of_ids)) print query
Może to zadziałać w niektórych przypadkach użycia, jeśli nie chcesz zajmować się metodą, w której musisz przekazać argumenty, aby uzupełnić ciąg zapytania i chciałbyś tylko wywołać
cursror.execute(query)
.Innym sposobem może być:
"select * from table where x in (%s)" % ', '.join(str(id) for id in list_of_ids)
źródło
Bardzo proste: po prostu użyj poniższej formacji
rules_id = ["9", "10"]
sql1 = "WYBIERZ * FROM attance_rules_staff WHERE id in (" + "," .join (map (str, rules_id)) + ")"
„,” .join (map (str, rules_id))
źródło
rules_id
zawiera"); DROP TABLES Bobby --
?