2011-01-27 16 views
7

Używam pyodbc zapytań do bazy danych SQL ServerSQL IN operatora za pomocą pyodbc i SQL Server

import datetime 
import pyodbc  
conn = pyodbc.connect("Driver={SQL Server};Server='dbserver',Database='db', 
         TrustedConnection=Yes") 
cursor = conn.cursor() 
ratings = ("PG-13", "PG", "G") 
st_dt = datetime(2010, 1, 1) 
end_dt = datetime(2010, 12, 31) 
cursor.execute("""Select title, director, producer From movies 
       Where rating In ? And release_dt Between ? And ?""", 
       ratings, str(st_dt), str(end_dt)) 

ale otrzymuję błąd poniżej. Czy parametr krotki musi być obsługiwany w inny sposób? Czy istnieje lepszy sposób na skonstruowanie tego zapytania?

('42000', "[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Line 9: 
    Incorrect syntax near '@P1'. (170) (SQLExecDirectW); 
    [42000] [Microsoft][ODBC SQL Server Driver][SQL Server] 
    Statement(s) could not be prepared. (8180)") 

UPDATE:

udało mi się dostać to zapytanie do pracy za pomocą operatora formatowania ciąg, który nie jest idealny, ponieważ wprowadza obawy związane z bezpieczeństwem.

import datetime 
import pyodbc  
conn = pyodbc.connect("Driver={SQL Server};Server='dbserver',Database='db', 
         TrustedConnection=Yes") 
cursor = conn.cursor() 
ratings = ("PG-13", "PG", "G") 
st_dt = datetime(2010, 1, 1) 
end_dt = datetime(2010, 12, 31) 
cursor.execute("""Select title, director, producer From movies 
       Where rating In %s And release_dt Between '%s' And '%s'""" % 
       (ratings, st_dt, end_dt)) 

Odpowiedz

12

Nie można sparametryzować wiele wartości w klauzuli IN() stosując jeden parametr ciąg. Jedynym sposobem na osiągnięcie tego jest:

  1. Substytucja ciągu (tak jak ty).

  2. Utwórz sparametryzowane zapytanie w postaci IN (?, ?, . . ., ?), a następnie przekaż osobny parametr dla każdego posiadacza miejsca. Nie jestem ekspertem w Pythonie dla ODBC, ale wyobrażam sobie, że jest to szczególnie łatwe w języku takim jak Python. Jest to bezpieczniejsze, ponieważ uzyskujesz pełną wartość parametryzacji.

+1

Dla twojej drugiej opcji, trzeba by dynamicznie utworzyć instrukcję SQL na podstawie rozmiaru krotki, którą chciałbyś przejść do instrukcji IN? – user338714

+1

Możesz zrobić coś takiego: cursor.execute ("WYBIERZ * Z filmów, gdzie ocena IN ({})". format ("," .łącz ("?" * len (oceny))) , oceny) – rleelr

2

Problem to Twoja krotka. Połączenie ODBC oczekuje ciągu znaków, aby skonstruować zapytanie, a Ty wysyłasz krotkę pytona. I pamiętaj, że musisz poprawnie cytować ciąg znaków. Zakładam, że liczba ocen, których będziesz szukać, będzie różna. Prawdopodobnie jest lepszy sposób, ale mój pyodbc wydaje się być prosty i bezpośredni.

Spróbuj wykonać następujące czynności:

import datetime 
import pyodbc  
conn = pyodbc.connect("Driver={SQL Server};Server='dbserver',Database='db', 
         TrustedConnection=Yes") 

def List2SQLList(items): 
    sqllist = "%s" % "\",\"".join(items) 
    return sqllist 


cursor = conn.cursor() 
ratings = ("PG-13", "PG", "G") 
st_dt = datetime(2010, 1, 1) 
end_dt = datetime(2010, 12, 31) 
cursor.execute("""Select title, director, producer From movies 
       Where rating In (?) And release_dt Between ? And ?""", 
       List2SQLList(ratings), str(st_dt), str(end_dt)) 
+0

I” m nadal otrzymuje błąd "Niepoprawna składnia" dla pierwszego parametru. Czy pyodbc może traktować listę jak ciąg zamiast listy? – user338714

+0

Jego umieszczenie "wokół całego łańcucha Zobacz moją edycję – WombatPM

+0

Nadal otrzymuję błąd parametru.Znalazłem sposób, aby uzyskać zapytanie do pracy przy użyciu operatora formatu ciągu (zobacz moją aktualizację powyżej), a ponieważ ten kod będzie działał tylko lokalnie, obawy dotyczące bezpieczeństwa mogą zostać przeoczone, myślę, że kursor.executemany może być inną opcją – user338714

11

Aby rozwinąć na drugiej opcji Larry'ego - dynamicznie tworząc sparametryzowanego ciąg, użyłem następujących powodzeniem:

placeholders = ",".join("?" * len(code_list)) 
sql = "delete from dbo.Results where RESULT_ID = ? AND CODE IN (%s)" % placeholders 
params = [result_id] 
params.extend(code_list) 
cursor.execute(sql, params) 

daje następujące SQL z odpowiednimi parametrami:

delete from dbo.Results where RESULT_ID = ? AND CODE IN (?,?,?) 
Powiązane problemy