python - 一次查询多个参数的 Sqlite 并处理缺失值

标签 python sqlite list

是否有可能在 SQL 查询中执行类似的操作?也许提供一个列表作为输入参数? 我想要的日期是连续的,但并非所有日期都存在于数据库中。如果日期不存在,则结果应为“无”。

dates = [dt.datetime(2008,1,1), dt.datetime(2008,1,2), dt.datetime(2008,1,3), dt.datetime(2008,1,4), dt.datetime(2008,1,5)]
id = "361-442"
result = []
for date in dates:
    curs.execute('''SELECT price, date FROM prices where date = ? AND id = ?''', (date, id))
    query = curs.fetchall()
    if  query == []:
        result.append([None, arg])
    else:
        result.append(query)

最佳答案

要在 sqlite 中执行所有工作,您可以使用 LEFT JOIN 来填充带有 None 的缺失价格:

sql='''
SELECT p.price, t.date
FROM ( {t} ) t
LEFT JOIN price p
ON p.date = t.date
WHERE p.id = ?
'''.format(t=' UNION ALL '.join('SELECT {d!r} date'.format(d=d) for d in date))

cursor.execute(sql,[id])
result=cursor.fetchall()

但是,此解决方案需要在 Python 中形成一个(可能)巨大的字符串,以便创建包含所有所需日期的临时表。它不仅速度慢(包括 sqlite 创建临时表所花费的时间)而且还很脆弱:如果 len(date) 大于大约 500,则 sqlite 提高

OperationalError: too many terms in compound SELECT

如果您已经在某个其他表中拥有所有需要的日期,您也许可以解决这个问题。然后你可以用上面的丑陋的“UNION ALL”SQL替换 像

SELECT p.price, t.date
FROM ( SELECT date from dates ) t
LEFT JOIN price p
ON p.date = t.date

虽然这是一个改进,但我的 timeit 测试(见下文)表明在 Python 中完成部分工作仍然更快:


用 Python 完成部分工作:

如果您知道日期是连续的,因此可以表示为一个范围,那么:

curs.execute('''
    SELECT date, price
    FROM prices
    WHERE date <= ?
        AND date >= ?
        AND id = ?''', (max(date), min(date), id))

否则,如果日期是任意的,则:

sql = '''
    SELECT date, price
    FROM prices
    WHERE date IN ({s})
        AND id = ?'''.format(s={','.join(['?']*len(dates))})
curs.execute(sql,dates + [id])

要形成 result 列表,并为缺失的价格插入 None,您可以从 (date,price ) 对,并使用 dict.get() 方法来 当缺少 date 键时提供默认值 None:

result = dict(curs.fetchall())
result = [(result.get(d,None), d) for d in date]

请注意,为了将 dict 形成为从日期到价格的映射,我在 SQL 查询中交换了 dateprice 的顺序。


Timeit 测试:

我比较了这三个函数:

def using_sqlite_union():
    sql = '''
        SELECT p.price, t.date
        FROM ( {t} ) t
        LEFT JOIN price p
        ON p.date = t.date
    '''.format(t = ' UNION ALL '.join('SELECT {d!r} date'.format(d = str(d))
                                      for d in dates))
    cursor.execute(sql)
    return cursor.fetchall()

def using_sqlite_dates():
    sql = '''
        SELECT p.price, t.date
        FROM ( SELECT date from dates ) t
        LEFT JOIN price p
        ON p.date = t.date
    '''
    cursor.execute(sql)
    return cursor.fetchall()

def using_python_dict():
    cursor.execute('''
        SELECT date, price
        FROM price
        WHERE date <= ?
            AND date >= ?
            ''', (max(dates), min(dates)))

    result = dict(cursor.fetchall())
    result = [(result.get(d,None), d) for d in dates]
    return result

N = 500
m = 10
omit = random.sample(range(N), m)
dates = [ datetime.date(2000, 1, 1)+datetime.timedelta(days = i) for i in range(N) ]
rows = [ (d, random.random()) for i, d in enumerate(dates) if i not in omit ]

rows 定义了插入到 price 表中的数据。


Timeit 测试结果:

运行时间是这样的:

python -mtimeit -s'import timeit_sqlite_union as t' 't.using_python_dict()'

产生了这些基准:

·────────────────────·────────────────────·
│  using_python_dict │ 1.47 msec per loop │
│ using_sqlite_dates │ 3.39 msec per loop │
│ using_sqlite_union │ 5.69 msec per loop │
·────────────────────·────────────────────·

using_python_dictusing_sqlite_dates 快 2.3 倍。即使我们将日期总数增加到 10000,速度比也保持不变:

·────────────────────·────────────────────·
│  using_python_dict │ 32.5 msec per loop │
│ using_sqlite_dates │ 81.5 msec per loop │
·────────────────────·────────────────────·

结论:将所有工作转移到 sqlite 中不一定更快。

关于python - 一次查询多个参数的 Sqlite 并处理缺失值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8751531/

相关文章:

sqlite - SQLite 数据库的校验和?

python - 跟踪Python元组中值的增量和减量

python - Windows 上没有适用于 Python 3.5 的 cx_Oracle 吗?

python - Bluehost:Python/CGI shebang 需要指向我安装的 Python?

python - Spark - 如何从数据集中提取 n 行?

java - 返回接口(interface)对象的列表

java - 如何通过系统属性将数组或值列表传递给 Java,以及如何访问它?

python - 在同一单元格中绘制图

python - excel.make_response_from_query_sets 返回 TypeError None

sqlite - 执行查询时出现 DatabaseIOException "Delete"