2012-06-25 6 views
6

Próbuję utworzyć oświadczenie następująco:jak formatować ciąg SQL w klauzuli z Pythonem

SELECT * FROM table WHERE provider IN ('provider1', 'provider2', ...) 

Jednak mam pewne problemy z formatowaniem string go z API Django. Oto co mam do tej pory:

profile = request.user.get_profile() 
providers = profile.provider.values_list('provider', flat=True) # [u'provider1', u'provider2'] 
providers = tuple[str(item) for item in providers] # ('provider1', 'provider2') 

SQL = "SELECT * FROM table WHERE provider IN %s" 
args = (providers,) 
cursor.execute(sql,args) 

DatabaseError 
(1241, 'Operand should contain 1 column(s)') 
+4

ciekawy. Dlaczego wykonujesz surowe zapytanie sql 'IN', gdy masz już ORM Django? – jdi

+0

@jdi Jest to długie zapytanie sql, które buduję z łączeniem ciągów na podstawie pewnych wprowadzonych przez użytkownika wartości (około 20 linii). – David542

+0

ORM ma jednak agregacje. Ale myślę, że muszę po prostu wierzyć na słowo, że ORM nie może tego zrobić :-) – jdi

Odpowiedz

4

MySQLdb ma sposobu, aby pomóc w ten sposób:

Doc

string_literal (...) string_literal (obj) - konwertuje obiekt obj do literału SQL. Oznacza to, że wszelkie specjalne znaki SQL są znakami ucieczkowymi i są zawarte w w pojedynczym cudzysłowie. Innymi słowy, to wykonuje:

"'%s'" % escape_string(str(obj)) 

Use connection.string_literal(obj), if you use it at all. 
_mysql.string_literal(obj) cannot handle character sets. 

Wykorzystanie

# connection: <_mysql.connection open to 'localhost' at 1008b2420> 

str_value = connection.string_literal(tuple(provider)) 
# '(\'provider1\', \'provider2\')' 

SQL = "SELECT * FROM table WHERE provider IN %s" 
args = (str_value,) 
cursor.execute(sql,args) 
+0

to całkiem fajne.Nie wiedziałem o metodzie string_literal. Zakładam, że ponieważ MySQLdb dość ściśle stosuje się do db api, to istnieje w większości implementacji? (Sqlite3, postgres, itp.) Zdecydowanie wracając do dokumentów –

+0

@ Justin.Wood: Szczerze mówiąc, tak naprawdę nie wiedziałem o tym albo, ale nie mam zbyt dużego doświadczenia przy korzystaniu z MySQLdb i przekazywaniu wartości krotek. To zawsze ORM. Po prostu przyjrzałem się dokumentom również dla tego :-) – jdi

+0

Schludny. Pracuję w starszej wersji kodu, która nie korzysta z ORM-a, i otrzymujemy to ciągle. To będzie dla mnie duży plus. Masz link do tego w dokumentach? Nie mogłem go znaleźć. Chociaż łatwo znaleźć w źródle. –

-1
"SELECT * FROM table WHERE provider IN ({0},{1},{2})".format(*args) #where args is list or tuple of arguments. 
+1

Jest to trochę ograniczone, ponieważ zakłada długość listy, prawda? – jdi

0

należy prawdopodobnie zrobić wymianę strun przed przekazaniem go do obiektu kursora do wykonania:

sql = "SELECT * FROM table WHERE provider IN (%s)" % \ 
     (','.join(str(x) for x in providers)) 
cursor.execute(sql) 
+0

Może to być problematyczne, ponieważ ciągi nie są cytowane. Może wymienić 'str' na' repr'? – jdi

+0

może również dodawać cytaty do łączenia, np. '% ('' '+'", "'. join (str (x) dla x w dostawcach) +" "')' - to może być postrzegane jako trochę hackowe, chociaż myślę, że jest to –

+0

Ale myślę, że jest to wymagane rozwiązanie. – jdi

-1

Tak, masz wejście ciąg dla identyfikatora wymagane:

some_vals = '1 3 5 76 5 4 2 5 7 8'.split() # convert to suitable type if required 
SomeModel.objects.filter(provider__in=some_vals) 
+0

Tak, zapytałem o to w głównych komentarzach OP powiedział, że istnieje szczególny powód, dla którego szukają surowego zapytania – jdi

+0

@jdi Interesujące - jeśli obiekt znajduje się wewnątrz ORM, zapytanie SQL można pobrać z tego W przeciwnym razie, mogę tylko myśleć, że pytają o coś spoza ORM –

+0

Jestem całkowicie z tobą w tym, na pewno.Możemy tylko założyć, że OP ma potrzeby, których ORM po prostu nie może spełnić – jdi

-1

powinien spróbować tego .... praca.

SQL = "SELECT * FROM table WHERE provider IN %s"%(providers) 
exec 'cursor.execute("%s")'%(SQL) 
0

Inna odpowiedź, że nie podoba mi się szczególnie, ale będzie pracować dla swojej pozornej użytkowej przypadku:

providers = tuple[str(item) for item in providers] # ('provider1', 'provider2') 
# rest of stuff... 

SQL = 'SELECT * FROM table WHERE provider IN {}'.format(repr(providers)) 
cursor.execute(SQL) 
+0

Można również napisać '' ... {! r} .format (dostawcy) 'Chyba - tylko zależy od gustu –