客至汲泉烹茶, 抚琴听者知音

sqlite3条件查询问题汇总

之前用tushare分析股票时,数据库选择了sqlite,原因很简单,它轻量,甚至不需要安装,python自带。但是今天从sqlite读取数据时,发现了一个很严重的问题:无法查询字符串。折腾了一晚上,终于搞定了。在这里记录一下sqlite的相关查询语法以及问题、解决方案。

查询数值型数据

sqlite的语法和mysql非常类似,因此可以直接使用select语法进行查询。我们以stock.db数据库中的limit_data表为例,查询收盘价为1.81的所有记录:

import sqlite3
conn = sqlite3.connect(r'E:\Finance\stock.db')
cursor = conn.cursor() # 获取一个光标
cursor.execute('SELECT * FROM  {0} where close = {1}'.format('limit_data',1.81)) # 执行查询
result = cursor.fetchall() # 获取结果
print(result)

结果返回一个列表

[('600610.SH', '20190102', '*ST毅达', 1.81, 5.23, 0.0, 543.7526, 1.0417, 7081263.0, '09:25:04', '09:25:04', 0, 84.03134, 'U'),
……
]

查询字符型数据

接下来查询trade_date为20190102的所有记录,查询命令改一下就行,注意trade_date是string

cursor.execute('SELECT * FROM  {0} where trade_data = {1}'.format('limit_data','20190102'))

成功返回数据,看来也是可行的。

[('600399.SH', '20190102', '*ST抚钢', 2.63, 5.2, 0.0, 2024.7509, 0.3159, 16382665.0, '09:25:04', '09:25:04', 0, 100.0, 'U'),
……]

再换一个条件试试,查询一下股票代码ts_code600399.SH的记录。

cursor.execute('SELECT * FROM  {0} where ts_code = {1}'.format('limit_data','600399.SH'))

报错:OperationalError: unrecognized token: "600399.SH",按理说不应该啊,这条记录明明存在啊。

试试其他string?查询name中山金马的记录。

cursor.execute('SELECT * FROM  {0} where name = {1}'.format('limit_data','中山金马'))

依然报错,而且报的错误类型还不一样,OperationalError: no such column: 中山金马

再试一下查询limitU(涨停板)?

cursor.execute('SELECT * FROM  {0} where limit = {1}'.format('limit_data','U'))

ok,第三种错误类型出现了,OperationalError: near "limit": syntax error

问题解决

上网查了好久,有人说是原始数据有问题,有人说占位符用错了(他们习惯用?来表示占位符),还有人说sqlite3的版本太旧,需要更新。

一一试过之后,没有一个能解决这个问题的。我甚至一度下载了mysql,但终究是太过繁琐而且笨重,所以放弃了安装。

最后试了各种方法,我终于发现:原来还是我写的语法有问题,对于字符串,要用引号把{}括起来。也就是说,上面的代码应该是这样的:

cursor.execute('SELECT * FROM  {0} where ts_code = "{1}"'.format('limit_data','600399.SH'))
cursor.execute('SELECT * FROM  {0} where name = "{1}"'.format('limit_data','中山金马'))

对于OperationalError: unrecognized tokenOperationalError: no such column错误类型,就可以解决了。但是OperationalError: near "limit": syntax error依然存在,猜测limit与python或sqlite3内置变量名冲突。(带*同样报这样的错)

那试试转义吧:

cursor.execute('SELECT * FROM  {0} where "{1}" = "{2}"'.format('limit_data',r'limit','U'))

成功返回结果!

总结

和mysql不一样,sqlite的condition必须要用引号括起来。

如果你碰到OperationalError: unrecognized tokenOperationalError: no such column报错,很有可能是没有引号的原因。

如果碰到OperationalError: near "limit": syntax error,则有可能是列名与python(或sqlite3)内置函数名冲突,加个转义即可。

如果你不想费心思考虑各种条件,可以直接用以下语法,无论是条件是字符型还是数值型,无论有没有冲突,都可以完美执行查询。

cursor.execute('SELECT * FROM  {0} where "{1}" = "{2}"'.format('table',r'col','condition'))
# 0,1,2分别是表名、列名、条件

更新:in条件查询

conditionin ?时,需要注意两点,一是条件序列必须为tuple(集合),二是占位符{}不能用括号括起来。语法如下:

cursor.execute('SELECT * FROM  {0} where "{1}" in {2}'.format('limit_data',r'trade_date',tuple(trade_cal)))

添加新评论