2017-11-17 1 views
0

동적으로 MS Access 데이터베이스를 쿼리하고 팬더 데이터 프레임에 결과를 반환하는 스크립트를 작성하고 있습니다. 동적으로 쿼리를 변경하는 두 개의 매개 변수가 있습니다. 문자열 형식 지정 방법을 사용하여 다음 솔루션을 조합했습니다. 이 솔루션이 작동하는 동안 문자열 메서드를 사용하지 않는보다 안전한 솔루션을 찾고 있습니다. 공유 할 수있는 지식을 인정하십시오!Pandas 및 pyodbc를 사용한 동적 쿼리 - 문자열이 아닌 메서드 솔루션 찾기

감사합니다.

values1 = ('1','2') 
values2 = ('1','2','3') 

ServerName = r'pathtodb\\database.mdb' 
connStr = 'DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=%s;' %ServerName 
cnxn = pyodbc.connect(connStr) 
query = 'SELECT * FROM TABLE WHERE item in ({0}) and item2 in ({1})' 
query = query.format(','.join('?' * len(values1)), ','.join('?' * len(values2))) 
param_list = values1 + values2 
df = pd.read_sql_query(query, cnxn, params=param_list) 
print(df) 
+2

왜 현재의 방법은 안전하지 않은 생각 하는가? 배열의 실제 내용은 여전히 ​​매개 변수로 전달됩니다. 문자열 함수로하는 유일한 일은 각'IN'에 대한 매개 변수의 수를 설정하는 것입니다. 우리가 예방할 수있는 특정 사안이 있습니까? –

+1

매개 변수가 입력 양식 사용자 일 때만 걱정할 필요가 있습니다. 따라서 해당 항목이 유효한 항목이고 SQL injection에 영향을받지 않도록해야합니다. –

+0

데이터베이스 쿼리에 익숙하지 않아 SQL 주입에 대한 많은 "열정적 인"토론을 접했습니다. 내 솔루션은 문자열 메서드를 사용하여 쿼리를 구문 분석하기 때문에 필자는 약간의 "분석 마비"를 경험했습니다. – davetunes

답변

1

항목 값을 보유하고 간단하게 팬더 가져 오기 위해 가입, items1 및 items2 , 임시 테이블을 사용하는 것이 좋습니다. 실제로 JOIN 접근 방식은 IN() 절에 긴 목록보다 효율적입니다.

values1 = ('1','2') 
values2 = ('1','2','3') 

ServerName = r'C:\pathtodb\database.mdb' 
connStr = 'DRIVER={{Microsoft Access Driver (*.mdb, *.accdb)}};DBQ={0};'.format(ServerName) 
cnxn = pyodbc.connect(connStr) 

cur = cnxn.cursor() 

# CLEAN OUT OLD DATA AND APPEND NEW DATA 
cur.execute('DELETE FROM items1') 
cnxn.commit() 
cur.executemany('INSERT INTO items1 ([item]) VALUES (?)', values1) 
cnxn.commit() 

cur.execute('DELETE FROM items2') 
cnxn.commit() 
cur.executemany('INSERT INTO items2 ([item]) VALUES (?)', values2) 
cnxn.commit() 

# IMPORT JOIN QUERY INTO PANDAS (PARENTHESES ARE REQUIRED) 
query = '''SELECT * FROM (TABLE t 
     INNER JOIN items1 i1 ON t.[item] = i1.[item]) 
     INNER JOIN items2 i2 ON t.[item2] = i2.[item] 
''' 

df = pd.read_sql_query(query, cnxn) 
print(df) 

대체 쿼리 :

query = '''SELECT * FROM TABLE 
     WHERE item IN (SELECT [item] FROM items1) 
      AND item2 IN (SELECT [item] FROM items2) 
'''