2017-07-14 60 views
0

我使用sql包在Jupyter筆記本電腦,我知道如何在我的查詢中使用的變量:如何使用Python列表%SQL查詢

client = "Disney" 
queryid = %sql SELECT * FROM mytable WHERE name = :client 

我不明白的是如何通過我的查詢列表,如:

clients = ["Disney", "Netflix", "Sky"] 
queryid = %sql SELECT * FROM mytable WHERE name in (:clients) 

這會產生一個錯誤,指出我的SQL是錯誤的。在此設置中處理列表的方式是什麼?

+0

如果你傳遞一個列表,你確定'='運算符仍然有效嗎?你可能需要'IN'或類似的東西。 –

+0

你想要什麼?與列表中的任何事物相匹配的項目? – hpaulj

+0

有關'where in in'的其他SO問題將列表字符串連接成一個字符串:https://stackoverflow.com/questions/283645/python-list-in-sql-query-as-parameter – hpaulj

回答

0

隨着演示案例sqlite3

In [1]: import sqlite3 
In [2]: conn = sqlite3.connect('example.db') 
In [3]: c = conn.cursor() 
In [4]: c.execute('''CREATE TABLE stocks 
    ...:    (date text, trans text, symbol text, qty real, price real)''') 
    ...: 
    ...: # Insert a row of data 
    ...: c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.1 
    ...: 4)") 
    ...: 
    ...: # Save (commit) the changes 
    ...: conn.commit() 
    ...: 
In [5]: # Larger example that inserts many records at a time 
    ...: purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00), 
    ...:    ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00), 
    ...:    ('2006-04-06', 'SELL', 'IBM', 500, 53.00), 
    ...:    ] 
    ...: c.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases) 

我可以獲取與匹配多個字符串值:

In [31]: c.execute('SELECT * FROM stocks WHERE symbol IN (?,?)',('IBM','RHAT')) 
Out[31]: <sqlite3.Cursor at 0xaf703fa0> 
In [32]: c.fetchall() 
Out[32]: 
[('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14), 
('2006-03-28', 'BUY', 'IBM', 1000.0, 45.0), 
('2006-04-06', 'SELL', 'IBM', 500.0, 53.0)] 

或者從Parameter substitution for a SQLite "IN" clause

In [33]: alist=['RHAT','IBM'] 
In [34]: c.execute('SELECT * FROM stocks WHERE symbol IN (%s)' % 
    ...:       ','.join('?'*len(alist)), 
    ...:       alist) 
    ...:        
Out[34]: <sqlite3.Cursor at 0xaf703fa0> 
In [35]: c.fetchall() 
Out[35]: 
[('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14), 
('2006-03-28', 'BUY', 'IBM', 1000.0, 45.0), 
('2006-04-06', 'SELL', 'IBM', 500.0, 53.0)] 

c.execute('SELECT * FROM stocks WHERE symbol IN (:1,:2)',alist)廣義解以及其他可能的形式。

還看到:

sqlite3 "IN" clause

我認爲MYSQL%sql iterface行爲相同;但我沒有安裝。


通過適當的引用文字也行(再次sqlite3

c.execute('SELECT * FROM stocks WHERE symbol IN ("IBM","RHAT")') 

In [80]: 'SELECT * FROM stocks WHERE symbol IN (%s)'%','.join('"%s"'%x for x in alist) 
Out[80]: 'SELECT * FROM stocks WHERE symbol IN ("RHAT","IBM")' 
In [81]: c.execute(_) 

所以我猜:

%sql SELECT * FROM stocks WHERE symbol IN ("IBM","RHAT") 

會即使工作某種形式的(:....)沒有。


我安裝%sql

In [5]: %%sql 
    ...: sqlite:///example.db 
    ...: 

Out[5]: 'Connected: [email protected]' 
In [7]: %sql SELECT * from stocks 
Done. 
Out[7]: 
[('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14), 
('2006-03-28', 'BUY', 'IBM', 1000.0, 45.0), 
('2006-04-05', 'BUY', 'MSFT', 1000.0, 72.0), 
('2006-04-06', 'SELL', 'IBM', 500.0, 53.0)] 

In [9]: %sql SELECT * from stocks where symbol in ('IBM') 
Done. 
Out[9]: 
[('2006-03-28', 'BUY', 'IBM', 1000.0, 45.0), 
('2006-04-06', 'SELL', 'IBM', 500.0, 53.0)] 

In [10]: %sql SELECT * from stocks where symbol in ('IBM','RHAT') 
Done. 
Out[10]: 
[('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14), 
('2006-03-28', 'BUY', 'IBM', 1000.0, 45.0), 
('2006-04-06', 'SELL', 'IBM', 500.0, 53.0)] 

字符串格式化方法的工作原理:

In [11]: alist=['RHAT','IBM'] 
In [12]: cmd='SELECT * FROM stocks WHERE symbol IN (%s)'%','.join('"%s"'%x for x 
    ...: in alist) 
In [13]: cmd 
Out[13]: 'SELECT * FROM stocks WHERE symbol IN ("RHAT","IBM")' 
In [14]: %sql $cmd 
Done. 
Out[14]: 
[('2006-01-05', 'BUY', 'RHAT', 100.0, 35.14), 
('2006-03-28', 'BUY', 'IBM', 1000.0, 45.0), 
('2006-04-06', 'SELL', 'IBM', 500.0, 53.0)] 

:語法是不是有據可查的。目前尚不清楚誰在實施它。 ($是標準的Ipython變量替換)。

In [18]: sym='IBM' 
In [19]: %sql SELECT * from stocks where symbol in (:sym) 
Done. 
Out[19]: 
[('2006-03-28', 'BUY', 'IBM', 1000.0, 45.0), 
('2006-04-06', 'SELL', 'IBM', 500.0, 53.0)] 

symbol in (:sym1,:sym2)工作

到目前爲止,我沒有看到證據表明%sql作品與傳統的SQL語法的佔位符。


看起來你提交併關閉在GitHub上一個問題,https://github.com/catherinedevlin/ipython-sql/issues/92

適應該解決方案引用字符串(?):

In [74]: mystring = '({})'.format(','.join('"{}"'.format(e) for e in alist)) 
In [75]: mystring 
Out[75]: '("RHAT","IBM")' 
In [76]: %sql SELECT * from stocks where symbol in $mystring 
Done. 

換句話說,使用ipython$注入作爲反對:的形式。


綜觀ipython-sql源代碼:

ipython-sql/blob/master/src/sql/run.py 
def run(conn, sql, config, user_namespace): 
    ... 
    txt = sqlalchemy.sql.text(statement) 
    result = conn.session.execute(txt, user_namespace) 

它看起來像:name語法是一個sqlalchemy綁定參數,並與sqlalchemy.sql.textsqlalchemy.sql.bindparam

http://docs.sqlalchemy.org/en/latest/orm/tutorial.html#orm-tutorial-literal-sql

處理

此錯誤表示每個綁定參數都被翻譯爲int ○?佔位符,再加上作爲選配parameters項:

In [96]: %sql SELECT * from stocks where symbol in :mystring 
(sqlite3.OperationalError) near "?": syntax error [SQL: 'SELECT * from stocks where symbol in ?'] [parameters: ('("RHAT","IBM")',)] 

所以我原來的產生IN (?,?,...)以匹配列表的長度的解決方案是正確的SQL,即使它不與sqlalchemy%sql工作。

+0

感謝您的時間,但正如我之前所說,無論您有%sql的解決方案,或者您沒有... – user299791

+0

我已經下載了' sql'並得到了一個使用'Ipython'' $'語法的解決方案。傳統的SQL佔位符語法顯然不適用於'%sql'和'sqlalchemy',它有自己的'bindparameters'語法。 – hpaulj