매개 변수로 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.