Mam listę Pythona, powiedz l
l = [1,5,8]
Chcę napisać zapytanie sql, aby uzyskać dane dla, powiedzmy, wszystkich elementów listy
select name from students where id = |IN THE LIST l|
Jak to osiągnąć?
Mam listę Pythona, powiedz l
l = [1,5,8]
Chcę napisać zapytanie sql, aby uzyskać dane dla, powiedzmy, wszystkich elementów listy
select name from students where id = |IN THE LIST l|
Jak to osiągnąć?
Odpowiedzi:
Odpowiedzi do tej pory umieszczały wartości w postaci zwykłego ciągu SQL. Jest to absolutnie w porządku w przypadku liczb całkowitych, ale jeśli chcemy to zrobić dla łańcuchów, pojawia się problem ze ucieczką.
Oto wariant używający sparametryzowanego zapytania, który zadziała w obu przypadkach:
placeholder= '?' # For SQLite. See DBAPI paramstyle.
placeholders= ', '.join(placeholder for unused in l)
query= 'SELECT name FROM students WHERE id IN (%s)' % placeholders
cursor.execute(query, l)
([placeholder]*len(l))
w ogólnym przypadku musi to być, ponieważ symbol zastępczy może mieć wiele znaków.
cursor.execute(f'SELECT name FROM students WHERE id IN ({','.join('?' for _ in l)})', l)
. @bobince, powinieneś również zauważyć w swoim rozwiązaniu, że używanie ?
jest bezpiecznym sposobem na uniknięcie iniekcji SQL. Jest tutaj wiele odpowiedzi, które są podatne na ataki, w zasadzie te, które łączą ciągi znaków w Pythonie.
Najłatwiej jest obrócić listę na tuple
pierwszą
t = tuple(l)
query = "select name from studens where id IN {}".format(t)
Nie komplikuj tego, rozwiązanie tego jest proste.
l = [1,5,8]
l = tuple(l)
params = {'l': l}
cursor.execute('SELECT * FROM table where id in %(l)s',params)
Mam nadzieję, że to pomogło !!!
l
zawiera tylko jeden element, skończysz id IN (1,)
. Co jest błędem składniowym.
sqlite3
. Z jaką biblioteką to przetestowałeś?
Żądany SQL to
select name from studens where id in (1, 5, 8)
Jeśli chcesz zbudować to z Pythona, możesz użyć
l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join(map(str, l)) + ')'
Funkcja map przekształci listę w listę ciągów, które można skleić przecinkami przy użyciu metody str.join .
Alternatywnie:
l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join((str(n) for n in l)) + ')'
jeśli wolisz wyrażenia generatora od funkcji mapy.
UPDATE: S. Lott wspomina w komentarzach, że powiązania Python SQLite nie obsługują sekwencji. W takim przypadku możesz chcieć
select name from studens where id = 1 or id = 5 or id = 8
Wygenerowane przez
sql_query = 'select name from studens where ' + ' or '.join(('id = ' + str(n) for n in l))
ciąg. dołącz wartości listy oddzielone przecinkami i użyj operatora formatu, aby utworzyć ciąg zapytania.
myquery = "select name from studens where id in (%s)" % ",".join(map(str,mylist))
(Dzięki, blair-conrad )
%
Byt używany tutaj jest po prostu Python ciąg formatowania.
Podoba mi się odpowiedź Bobince'a:
placeholder= '?' # For SQLite. See DBAPI paramstyle.
placeholders= ', '.join(placeholder for unused in l)
query= 'SELECT name FROM students WHERE id IN (%s)' % placeholders
cursor.execute(query, l)
Ale zauważyłem to:
placeholders= ', '.join(placeholder for unused in l)
Można wymienić na:
placeholders= ', '.join(placeholder*len(l))
Uważam, że jest to bardziej bezpośrednie, jeśli mniej sprytne i mniej ogólne. Tutaj l
wymagana jest długość (tj. Odwołanie się do obiektu, który definiuje __len__
metodę), co nie powinno stanowić problemu. Ale symbol zastępczy musi również być pojedynczym znakiem. Aby obsługiwać wieloznakowy symbol zastępczy:
placeholders= ', '.join([placeholder]*len(l))
Rozwiązanie dla odpowiedzi @umounted, ponieważ zostało przerwane z jednoelementową krotką, ponieważ (1,) nie jest poprawnym kodem SQL .:
>>> random_ids = [1234,123,54,56,57,58,78,91]
>>> cursor.execute("create table test (id)")
>>> for item in random_ids:
cursor.execute("insert into test values (%d)" % item)
>>> sublist = [56,57,58]
>>> cursor.execute("select id from test where id in %s" % str(tuple(sublist)).replace(',)',')'))
>>> a = cursor.fetchall()
>>> a
[(56,), (57,), (58,)]
Inne rozwiązanie dla ciągu sql:
cursor.execute("select id from test where id in (%s)" % ('"'+'", "'.join(l)+'"'))
placeholders= ', '.join("'{"+str(i)+"}'" for i in range(len(l)))
query="select name from students where id (%s)"%placeholders
query=query.format(*l)
cursor.execute(query)
To powinno rozwiązać twój problem.
Jeśli używasz PostgreSQL z biblioteką Psycopg2, możesz pozwolić jej adaptacji krotek na wykonanie wszystkich znaków ucieczki i interpolacji ciągów, np .:
ids = [1,2,3]
cur.execute(
"SELECT * FROM foo WHERE id IN %s",
[tuple(ids)])
czyli po prostu upewnij się, że przekazujesz IN
parametr jako plik tuple
. jeśli to a list
, możesz użyć = ANY
składni tablicy :
cur.execute(
"SELECT * FROM foo WHERE id = ANY (%s)",
[list(ids)])
zwróć uwagę, że oba zostaną przekształcone w ten sam plan zapytań, więc powinieneś po prostu użyć tego, który jest łatwiejszy. np. jeśli twoja lista znajduje się w krotce, użyj pierwszej, jeśli jest przechowywana w liście, użyj drugiej.
prostsze rozwiązanie:
lst = [1,2,3,a,b,c]
query = f"""SELECT * FROM table WHERE IN {str(lst)[1:-1}"""
l = [1] # or [1,2,3]
query = "SELECT * FROM table WHERE id IN :l"
params = {'l' : tuple(l)}
cursor.execute(query, params)
:var
Zapis wydaje się prostsze. (Python 3.7)
To używa podstawiania parametrów i zajmuje się przypadkiem listy pojedynczej wartości:
l = [1,5,8]
get_operator = lambda x: '=' if len(x) == 1 else 'IN'
get_value = lambda x: int(x[0]) if len(x) == 1 else x
query = 'SELECT * FROM table where id ' + get_operator(l) + ' %s'
cursor.execute(query, (get_value(l),))
','.join(placeholder * len(l))
byłby nieco krótszy, a nadal czytelny