2014-06-25 17 views
22

Czy istnieją przykłady przekazywania parametrów za pomocą zapytania SQL w Pandach?Pandy read_sql z parametrami

W szczególności używam silnika SQLAlchemy do łączenia się z bazą danych PostgreSQL. Do tej pory znalazłem, że następujące utwory:

df = psql.read_sql(('select "Timestamp","Value" from "MyTable" ' 
        'where "Timestamp" BETWEEN %s AND %s'), 
        db,params=[datetime(2014,6,24,16,0),datetime(2014,6,24,17,0)], 
        index_col=['Timestamp']) 

Dokumentacja Pandy mówi, że params może być również przekazywane jako dict, ale nie wydaje się uzyskać to do pracy próbowałem na przykład:

df = psql.read_sql(('select "Timestamp","Value" from "MyTable" ' 
        'where "Timestamp" BETWEEN :dstart AND :dfinish'), 
        db,params={"dstart":datetime(2014,6,24,16,0),"dfinish":datetime(2014,6,24,17,0)}, 
        index_col=['Timestamp']) 

Jaki jest zalecany sposób uruchamiania tego typu zapytań z Pand?

Odpowiedz

31

The read_sql docs powiedzieć params argument może być lista, krotki lub dict (patrz docs).

do przekazania wartości zapytania SQL, istnieją różne możliwe składnie: ?, :1, :name, %s, %(name)s (patrz PEP249).
Ale nie wszystkie z tych możliwości są obsługiwane przez wszystkie sterowniki bazy danych, , która to składnia jest obsługiwana, zależy od sterownika, którego używasz w swojej sytuacji: (psycopg2 w twoim przypadku).

W swoim drugim przypadku, gdy przy użyciu dict, używasz argumentów nazwanych „”, a zgodnie z dokumentacją psycopg2, wspierają one styl %(name)s (a więc nie :name przypuszczam), patrz http://initd.org/psycopg/docs/usage.html#query-parameters.
więc użycie że styl powinno działać:

df = psql.read_sql(('select "Timestamp","Value" from "MyTable" ' 
        'where "Timestamp" BETWEEN %(dstart)s AND %(dfinish)s'), 
        db,params={"dstart":datetime(2014,6,24,16,0),"dfinish":datetime(2014,6,24,17,0)}, 
        index_col=['Timestamp']) 
+0

To bardzo pomocne - używam psycopg2, więc składnia '% (nazwa) działa idealnie. – tobycoleman

+0

Prawdopodobnie wspomnimy o tym w docstringu: https: //github.com/pydata/pandas/issues/7573 – joris

+0

To rozwiązanie nie działa już na PostgreSzu - należy użyć ': notation', a następnie upewnić się zawijać ciąg SQL za pomocą 'sqlalchemy.text()' – hamx0r

1

Używam tej konfiguracji z SQLite, co oznacza, że ​​mogę obsługiwać parametry w Pythonie, a nie w Pandach. Działa dobrze dla mnie i łatwiejsze do odczytania, a następnie rzuca zapytanie i parametry bezpośrednio do read_sql.

con = sqlite3.connect("mydb.db") 

verses_sql = '''SELECT 
        kjv.b, 
        kjv.id, 
        kjv.t, 
        kjv.v, 
        ke.n, 
        ke.author 
       FROM t_kjv kjv 
       LEFT JOIN key_english ke on kjv.b = ke.b 
       WHERE blah = %s''' % blah 

df_verses = pd.read_sql(verses_sql, con, index_col='id') 

Robi to w ten sposób oznacza, że ​​można również przekazać dict do multilinii ciąg jeśli wolisz:

>>> d = { 'vars': "variables", 'example': "example" } 
>>> s = "This is an {example} with {vars}" 
>>> s.format(**d) 
'This is an example with variables' 
+0

Czy ktoś za pomocą tego z Sybase i sqlanydb? – toasteez

+7

Oznacza to również, że w ten sposób można wstrzyknąć znacznie więcej rzeczy niż tylko wartości. W rzeczywistości pozwala modyfikować naturę samego zapytania. Takie podejście jest podatne na [SQL Injection] (https://www.google.com/search?q=sql+injection), stąd potrzeba użycia zmiennych bind. – YoYo

+0

@toasteez to część podstawienia łańcucha znaków Pythona i nie ma nic wspólnego z SQL. Jest więc niezależny od używanej bazy danych i działa równie dobrze. Zwróć uwagę na element SQL Injection. – YoYo