使用 LIMIT 通过 SQLite 进行分页

Dev*_*lus 2 sql sqlite limit

我正在编写自己的 SQLIteBrowser,并且有最后一个问题,这显然在网络上经常讨论,但似乎没有一个好的通用解决方案。

所以目前我存储用户输入的SQL。每当我需要获取行时,我都会通过在 SQL 末尾添加“Limit n, m”来执行 SQL。

对于我主要使用的普通 SQL,这似乎已经足够了。但是,如果我想在查询中使用 limit 自己,这显然会给出错误,因为生成的 sql 可能如下所示:

 select * from table limit 30 limit 1,100
Run Code Online (Sandbox Code Playgroud)

这显然是错误的。有更好的方法来做到这一点吗?

我的想法是,我可以扫描 SQL 并检查是否已经使用了限制子句,然后忽略它。当然它不是那么简单,因为如果我有这样的sql:

 select * from a where a.b = ( select x from z limit 1)
Run Code Online (Sandbox Code Playgroud)

显然在这种情况下它仍然应该应用我的限制,所以我可以从末尾扫描字符串并查看是否存在限制。我现在的问题是,这有多可行。由于我不知道 SQL 解析器是谁工作的,所以我不确定 LIMIT 是否必须位于 SQL 的末尾,或者末尾是否还可以有其他命令。

我用order byand测试了它,如果不是最后,group by我会得到 SQL 错误,所以我的假设似乎是正确的。limit

Dev*_*lus 6

我现在找到了一个更好的解决方案,它非常简单,不需要我解析 SQL。

用户可以输入任意的sql。结果被加载到表中。由于我们不想一次加载整个结果,因为这可能会返回数百万条记录,因此只检索 N 条记录。当用户滚动到表格底部时,将获取接下来的 N 个项目并将其加载到表格中。

解决方案是,将 SQL 包装到具有页面大小限制的外部 SQL 中。

 select * from (arbitrary UserSQL) limit PageSize, CurrentOffset
Run Code Online (Sandbox Code Playgroud)

我用我经常使用的 SQL 对其进行了测试,这似乎工作得很好,而且对于我的目的来说也足够快。

但是,我不知道 SQLite 是否有更快地获取新行的机制,或者是否每次都必须重新运行 sql。在这种情况下,对于响应时间较长的非常复杂的查询来说,它可能不是一个好的解决方案。

  • 根据以下 SO 文章,限制 X, Y 使数据库实际上读取 Y 之前的所有内容,然后剥离 X 之前的所有内容,这使得效率非常低。更好地存储列中的一些值,例如时间戳或 id:http://stackoverflow.com/questions/14468586/efficient-paging-in-sqlite-with-millions-of-records (2认同)