2

我在表中有一些初始行。我想用递归调用来修改它们。在我的示例代码中,这个函数是一个简单的乘以 2,我想执行 5 次:

WITH RECURSIVE cte (n,v) AS
(

  -- initial values
  SELECT 0,2
  UNION ALL
  SELECT 0,3

  UNION ALL

  -- generator
  SELECT n + 1, v * 2 FROM cte WHERE n < 5
)
SELECT v FROM cte where n = 5;

它有效,但我的问题是它只在查询结束时过滤掉不需要的值。如果我从更多的行开始,它会降低性能,因为我应该在内存中有更多的行。是否可以仅在每次迭代中保留最新值?

SQLFiddle:http ://sqlfiddle.com/#!5/9eecb7/6761

4

2 回答 2

1

在 SQLite 中,您可以使用OFFSET 子句

  • 如果 OFFSET 子句存在并且具有正值 N,则它会阻止将前 N 行添加到递归表中。前 N 行仍然由递归选择处理——它们只是没有添加到递归表中。在跳过所有 OFFSET 行之前,不会将行计入完成 LIMIT。

演示:http ://sqlfiddle.com/#!5/9eecb7/6804

WITH RECURSIVE cte (n,v) AS
(

  -- initial values
  SELECT 0,2
  UNION ALL
  SELECT 0,3

  UNION ALL

  -- generator
  SELECT n + 1, v * 2 FROM cte WHERE n < 5 LIMIT 1000 OFFSET 10

)
SELECT * FROM cte

| n |  v |
|---|----|
| 5 | 64 |
| 5 | 96 |

在上面的示例中,偏移量计算为初始选择中的初始行数(2 行)乘以迭代次数(5)=> 2*5=10


顺便说一句,在这个具体的例子中,更好的解决方案是计算简单X * 2^5
(X 乘以 2 到 5 的幂)而不是递归。

于 2018-04-28T16:09:38.790 回答
1

在 SQLite 中,CTE 被实现为协程(如EXPLAIN输出所示),因此只有当前行保留在内存中,不会因内存使用而降低性能。

MySQL不允许在递归 SELECT 部分使用 LIMIT。如果我正确解释WL#3634,8.0版中的实现总是完全实现递归 CTE。

所以在 SQLite 中,你不需要做任何事情,而在 MySQL 中,你什么也做不了。

于 2018-04-29T08:22:01.617 回答