매개 변수로 SQL 쿼리의 파이썬 목록


124

파이썬 목록이 있습니다.

l = [1,5,8]

목록의 모든 요소에 대한 데이터를 가져 오는 SQL 쿼리를 작성하고 싶습니다.

select name from students where id = |IN THE LIST l|

어떻게해야합니까?

답변:


111

지금까지 답변은 값을 일반 SQL 문자열로 템플릿 화했습니다. 정수의 경우 절대적으로 괜찮지 만 문자열에 대해 수행하려면 이스케이프 문제가 발생합니다.

다음은 두 가지 모두에서 작동하는 매개 변수화 된 쿼리를 사용하는 변형입니다.

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)

11
','.join(placeholder * len(l))여전히 읽을 수 있지만 조금 더 짧을 것입니다 imho
ThiefMaster

7
@Thiefmaster : 예, ([placeholder]*len(l))자리 표시자가 여러 문자 일 수 있으므로 일반적인 경우에 있어야합니다.
bobince 2013 년

1
내 경우에는 @bobince 변수 a = 'john'및 b = 'snow'를 할당하고 got = [ 'a, b']라는 이름의 튜플에 저장하고 동일한 쿼리를 수행했습니다. 이렇게하면 erroy 즉 유형 오류가 발생했습니다. 문자열 형식화 중에 모든 인수가 변환되지는 않았습니다. 어떻게 해결해야하나요
TechJhola

2
이 작업을 dbapi에 맡기지 않고 "직접"참여하려는 이유는 무엇입니까? 키는 ... 목록보다는 튜플을 사용하는 것입니다
알레산드로 Dentella

5
이 답변을 기반으로 여기에 Python 3.6에 대한 한 줄 솔루션이 cursor.execute(f'SELECT name FROM students WHERE id IN ({','.join('?' for _ in l)})', l)있습니다. @bobince, 당신은 또한 ?SQL 주입을 피하는 측면에서 사용 이 안전한 방법 이라고 솔루션에 언급해야합니다 . 여기에는 취약한 많은 답변이 있습니다. 기본적으로 파이썬에서 문자열을 연결하는 모든 답변이 있습니다.
toto_tico

59

가장 쉬운 방법은 목록을 tuple처음 으로 바꾸는 것입니다.

t = tuple(l)
query = "select name from studens where id IN {}".format(t)

1
이것은 실제로 정답입니다. 왜 무시되었는지 잘 모르겠습니다. 먼저 목록 l을 설정 한 다음 튜플을 사용한 다음 튜플을 쿼리에 전달합니다. 잘 했어.
MEdwin

11
@renstrm에서 언급했듯이, 내가 하나의 요소 만 포함하면 작동하지 않으며 결국 ID IN (1,)이됩니다. 구문 오류입니다.
Doubledown

1
@Boris 입력이 항상 목록이라는 것을 보장 할 수 없다면 다음과 유사한 작업을 수행 할 수 있습니다. stackoverflow.com/questions/38821586/… 인수를 쿼리에 전달하기 전에
Amir Imani

10
이것은 허용되는 답변 이외의 대부분의 답변과 마찬가지로 SQL 주입에 취약하므로 사용해서는 안됩니다.
Bacon Bits

2
@BaconBits Fair 경고이지만 SQL 주입이 문제가되지 않는 일부 응용 프로그램 (예 : 내가 유일한 사용자 인 데이터베이스 분석)의 경우이 작업이 수행됩니다.
irene

26

그것을 복잡하게하지 마십시오. 이에 대한 해결책은 간단합니다.

l = [1,5,8]

l = tuple(l)

params = {'l': l}

cursor.execute('SELECT * FROM table where id in %(l)s',params)

여기에 이미지 설명 입력

이것이 도움이 되었기를 바랍니다 !!!


10
l하나의 요소 만 포함 하면 작동하지 않으며 id IN (1,). 구문 오류입니다.
renstrm

3
내가 하나의 요소 만 포함하는 경우 튜플인지 확인하고 작동합니다. 이 솔루션은 허용되는 것보다 내 생각에 더 명확합니다.
Alessandro Dentella

2
그러나 튜플이 비어 있으면 여전히 작동하지 않으므로 쿼리 실행 전에 추가 확인이 필요합니다.
Никита Конин apr

2
이것은 나를 위해 작동하지 않습니다 sqlite3. 어떤 라이브러리에 대해 테스트 했습니까?
Nick Chammas

1
좋은 해결책이지만 @renstrm과 Никита-Конин은 튜플에 단일 요소가 있거나 요소가 없을 때 추가 검사를 요구하는 것이 옳습니다.
Anish Sana

23

원하는 SQL은

select name from studens where id in (1, 5, 8)

파이썬에서 이것을 구성하려면 다음을 사용할 수 있습니다.

l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join(map(str, l)) + ')'

지도 기능은 사용 쉼표로 서로 접착 될 수있는 문자열리스트로 변환리스트 것이다 str.join의 방법.

또는 :

l = [1, 5, 8]
sql_query = 'select name from studens where id in (' + ','.join((str(n) for n in l)) + ')'

map 함수보다 생성기 표현식 을 선호하는 경우 .

업데이트 : S. Lott 는 주석에서 Python SQLite 바인딩이 시퀀스를 지원하지 않는다고 언급했습니다. 이 경우에는

select name from studens where id = 1 or id = 5 or id = 8

에 의해 생성 된

sql_query = 'select name from studens where ' + ' or '.join(('id = ' + str(n) for n in l))

2
:-( Python SQLite 바인딩은 시퀀스를 지원하지 않습니다.
S.Lott

오? 나는 깨닫지 못했다. 그런 다음 다시 SQLite 바인딩 솔루션을 사용한다는 것을 알지 못했습니다.
Blair Conrad

죄송합니다. SQLite를 제안하거나 암시하지 않습니다. 목록에 대한 바인딩이 작동하지 않는다는 사실이 슬프다.
S.Lott

11

string.join 쉼표로 구분하여리스트의 값을 사용하여 포맷 연산자 쿼리 스트링을 형성한다.

myquery = "select name from studens where id in (%s)" % ",".join(map(str,mylist))

(감사합니다, 블레어 콘래드 )


2
이 접근 방식은 데이터베이스 매개 변수 대체를 사용하지 않기 때문에 SQL 주입 공격에 노출됩니다. 여기서 %사용되는 것은 단순한 파이썬 문자열 형식입니다.
Nick Chammas

8

나는 bobince의 대답을 좋아합니다.

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)

그러나 나는 이것을 발견했습니다.

placeholders= ', '.join(placeholder for unused in l)

다음으로 대체 가능 :

placeholders= ', '.join(placeholder*len(l))

덜 영리하고 덜 일반적이라면 이것이 더 직접적이라고 생각합니다. 여기 l에 길이가 필요합니다 (즉, __len__메서드 를 정의하는 객체를 참조 ). 이는 문제가되지 않습니다. 그러나 자리 표시자는 단일 문자 여야합니다. 다중 문자 자리 표시자를 지원하려면 다음을 사용하십시오.

placeholders= ', '.join([placeholder]*len(l))

2

(1,)이 유효한 SQL이 아니기 때문에 단일 요소 튜플로 중단 되었기 때문에 @umounted 답변에 대한 솔루션입니다. :

>>> 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,)]

SQL 문자열에 대한 다른 솔루션 :

cursor.execute("select id from test where id in (%s)" % ('"'+'", "'.join(l)+'"'))

5
이것은 SQL 주입으로 인해 더 나은 솔루션이 아닙니다.
Anurag

2
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)

이것은 당신의 문제를 해결할 것입니다.


2

Psycopg2 라이브러리와 함께 PostgreSQL을 사용하는 경우 튜플 적응 이 모든 이스케이프 및 문자열 보간을 수행하도록 할 수 있습니다. 예 :

ids = [1,2,3]
cur.execute(
  "SELECT * FROM foo WHERE id IN %s",
  [tuple(ids)])

즉, IN매개 변수를 tuple. 그렇다면 배열 구문을list 사용할 수 있습니다 .= ANY

cur.execute(
  "SELECT * FROM foo WHERE id = ANY (%s)",
  [list(ids)])

둘 다 동일한 쿼리 계획으로 전환되므로 더 쉬운 것을 사용해야합니다. 예를 들어 목록이 튜플에 들어 있으면 전자를 사용하고 목록에 저장되어 있으면 후자를 사용하십시오.


1

예를 들어 SQL 쿼리를 원하는 경우 :

select name from studens where id in (1, 5, 8)

이건 어떤가요:

my_list = [1, 5, 8]
cur.execute("select name from studens where id in %s" % repr(my_list).replace('[','(').replace(']',')') )


1
l = [1] # or [1,2,3]

query = "SELECT * FROM table WHERE id IN :l"
params = {'l' : tuple(l)}
cursor.execute(query, params)

:var표기법은 간단 보인다. (Python 3.7)


0

이것은 매개 변수 대체를 사용하고 단일 값 목록 케이스를 처리합니다.

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),))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.