【问题标题】:how to use python list in %sql query如何在 %sql 查询中使用 python 列表
【发布时间】:2020-04-01 00:06:14
【问题描述】:

我在 Jupyter 笔记本中使用 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 错误。在此设置中处理列表的方式是什么?

【问题讨论】:

  • 如果您传递一个列表,您确定= 运算符仍然有效吗?你可能想要IN 或类似的东西。
  • 你想要什么?与列表中的任何内容匹配的项目?
  • 关于where in 的其他 SO 问题将列表字符串连接成一个字符串:stackoverflow.com/questions/283645/…
  • @hpaulj 关键是要为这种使用 MySQL 的特殊方式设置正确的 sintax
  • @cᴏʟᴅsᴘᴇᴇᴅ 是的,当然我会更新我的问题

标签: python mysql ipython jupyter


【解决方案1】:

带有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: None@example.db'
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)

此错误表明每个绑定参数都被转换为? 占位符,加上匹配的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

【讨论】:

  • 感谢您的宝贵时间,但正如我之前所说,您有 %sql 的解决方案,或者您没有...
  • 我已经下载了%sql 并得到了一个使用Ipython $ 语法的解决方案。传统的 SQL 占位符语法显然不适用于 %sqlsqlalchemy,它们有自己的 bindparameters 语法。
  • 这是一个非常彻底的答案,确实可以预见未来对这个问题的访问。 %sql 版本对我来说就像一个魅力。
【解决方案2】:

删除括号对我有用。

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

【讨论】:

    【解决方案3】:

    这个功能让我免于这种问题:

    
    > def splitParam(param): # this function splits multiple values of filter
        filteredParam = ""
        if param:
            for item in param:
                if filteredParam=="":
                    filteredParam += "'" + item.upper() + "'"
                else:
                    filteredParam += ", '" + item.upper() + "'"
    
        return filteredParam 
    

    【讨论】:

      【解决方案4】:

      关于在 SQL 查询中将 $ 与 python 元组一起应用的轶事说明:

      它需要在 %sql 行中使用,它不能*在 %%sql 代码块中使用。 使用续行反斜杠以提高查询的可读性。

      *据我所知

      【讨论】:

        猜你喜欢
        • 2015-08-07
        • 1970-01-01
        • 2021-08-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-02
        • 2019-08-28
        相关资源
        最近更新 更多