2010-02-12 4 views
8

Python의 DB API 사양을 사용하면 매개 변수의 인수를 execute() 메서드에 전달할 수 있습니다. 내 진술의 일부는 WHERE 절이 었으며 튜플을 사용하여 IN을 채 웠습니다. 예를 들면 :WHERE IN ... INT 목록에 대한 매개 변수 전달 .execute

params = ((3, 2, 1),) 
stmt = "SELECT * FROM table WHERE id IN %s" 
db.execute(stmt, params) 

하지만 매개 변수 튜플이 실패 실행 한 항목의 튜플 인 상황으로 실행할 때.

ProgrammingError: ERROR: syntax error at or near ")"
LINE 13: WHERE id IN (3,)

튜플을 올바르게 사용하려면 어떻게해야합니까?

답변

8

편집 : @rspeer 코멘트에서 언급 한 바와 같이, SQL 주입 공격으로부터 자신을 보호 할 수있는 예방 조치를 취할 마십시오. pg8000

테스트 (A DB-API PostgreSQL 데이터베이스 엔진 2.0 호환 순수 파이썬 인터페이스) :

이는 "IN"절에 여러 매개 변수를 전달하기 위해 권장되는 방법입니다.

params = [3,2,1] 
stmt = 'SELECT * FROM table WHERE id IN (%s)' % ','.join('%s' for i in params) 
cursor.execute(stmt, params) 

또 다른 편집 (완벽하게 테스트 및 작업 예)

는 :

>>> from pg8000 import DBAPI 
>>> conn = DBAPI.connect(user="a", database="d", host="localhost", password="p") 
>>> c = conn.cursor() 
>>> prms = [1,2,3] 
>>> stmt = 'SELECT * FROM table WHERE id IN (%s)' % ','.join('%s' for i in prms) 
>>> c.execute(stmt,prms) 
>>> c.fetchall() 
((1, u'myitem1'), (2, u'myitem2'), (3, u'myitem3')) 
+1

내가 틀렸다고 정정하되, 예제가 IN 하위 조항에만 첫 번째 항목 만 전달하면 안됩니까? > SELECT * FROM 테이블 어디에서 id (3) –

+0

@ 존 : 네가 맞아. 고마워. 추가 정보로 답변을 업데이트 중입니다. – bernie

+1

고마워요, Adam. –

1

오류가 쉼표 3 이후에 오는 것입니다. 단일 값에 대해 놔두면 설정됩니다.

params = ((3), ...) 
stmt = "SELECT * FROM table WHERE id IN %s" 
db.execute(stmt, params) 
+0

그래, 왜 오류가 발생했는지는 알지만 튜플을 만들지는 않습니다. 튜플은 다른 SQL 결과로 채워집니다. 따라서 전달하는 동안 단일 항목 튜플은 매달려있는 쉼표를 유지합니다. –

+0

또한 단일 항목 튜플에는 후행 쉼표가 있어야한다는 점을 지적하고자했습니다. –

+0

아, 나는 오해했다. 그런 경우에는 len()을 사용하여 튜플의 길이를 구할 수 있으며, 튜플의 길이를 구하면 튜플 [0]을 사용하여 쉼표없이 값을 추출 할 수 있습니다. – Daniel

1

이것은 당신이 질문을 정확하게 질문에 대답하지 않을 수 있습니다,하지만 난 당신이 가지고있는 문제를 해결할 수 있습니다 생각합니다.

파이썬의 DB-API는 튜플을 안전하게 대체 된 매개 변수로 전달하는 방법을 제공하지 않습니다. 허용 된 bernie의 대답은 안전을 위해 대체를 위해 Python % 연산자를 사용하고 있습니다.

그러나 튜플을 매개 변수로 전달할 필요는 없습니다. 특히 원하는 튜플이 다른 SQL 쿼리의 결과 인 경우 (Daniel에 명시한대로). 대신 SQL 하위 쿼리를 사용할 수 있습니다.

당신이 당신의 IN 절에서 원하는 ID의 설정 예를 들어 SELECT id FROM other_table WHERE use=true의 결과 인 경우 :

stmt = "SELECT * FROM table WHERE id IN (SELECT id FROM other_table WHERE use=true)" 
db.execute(stmt) 

는 그리고이도 (안전한 방법) 매개 변수화 할 수 있습니다. 선택하려는 ID가 주어진 parent_id 인 경우 :

stmt = "SELECT * FROM table WHERE id IN (SELECT id FROM other_table WHERE parent_id=%s)" 
params = (parent_id,) 
db.execute(stmt, params) 
0

허용되는 대답은 SQL 주입을 위험에 빠뜨립니다. 사용자 입력을 데이터베이스에 직접 전달해서는 안됩니다. 대신 정확한 수의 자리 표시자를 사용하여 쿼리를 생성 한 다음 pg8000이 이스케이프 처리를 수행하도록하십시오.

params = [3,2,1] 
# SELECT * from table where id in (%s,%s,%s) 
stmt = 'SELECT * FROM table WHERE id IN ({})'.format(','.join(['%s']*len(params))) 
cursor.execute(stmt, tuple(params)) 
+0

허용되는 답변의 내용과 동일하지 않습니까? 또한 쿼리 문자열에 직접 매개 변수를 대입하지 않고 올바른 수의 자리 표시자를 사용하여 쿼리를 생성합니다. – BrenBarn