这个递归SQL CTE是如何准确工作的



有人能向我解释一下这个SQL查询到底是如何工作的吗?

WITH recursive n(n) AS (
  SELECT 2 n
  UNION ALL
  SELECT n+1 FROM n WHERE n<1000
)
SELECT a.n
FROM n a
  LEFT JOIN n b
  ON b.n < sqrt(a.n)
GROUP BY a.n
HAVING a.n=2 OR MIN(a.n % b.n) > 0;

这将在PostgresQL中生成以下内容:

 n
====
251
887
601
647
577
...
9
(177 rows)

我对逐行分解的理解:

SELECT 2 n——选择数字2作为n【CTE的锚定成员】

CCD_ 2-与来自n<1000,因此显示从2到1000 的所有数字

SELECT a.n FROM n a——运行上述查询[CTE的递归成员]

LEFT JOIN n b-左将数字2-1000与第二组数字连接

ON b.n < sqrt(a.n)——其中第二组数字小于第一列数字的平方根?

GROUP BY a.n——只显示第一列数字

HAVING a.n=2 OR MIN(a.n. % b.n) > 0--。。。其中A=2或A模B的最小值大于0?

这是一个愚蠢的问题,但如果有任何帮助,我们将不胜感激。

正确修复查询后,会生成一个低于1000:的素数列表

WITH recursive n(n) AS (
  SELECT 2 n
  UNION ALL
  SELECT n+1 FROM n WHERE n<1000
)
SELECT a.n
FROM n a
  LEFT JOIN n b
  ON b.n <= sqrt(a.n)                        -- Fix #1
GROUP BY a.n
HAVING a.n=2 OR a.n=3 OR MIN(a.n % b.n) > 0  -- Fix #2
ORDER BY a.n ASC

演示。

解释相当简单:查询的递归部分只是提供一个从2(包括2)到1000(不包括1000)的数字列表。您可以将递归子句替换为一个实际的表,该表由连续的整数填充。

然后,这些数字被输入到查询的非CTE部分,并在条件b.n < sqrt(a.n)上连接到它们自己。CCD_ 9侧表示候选素数;CCD_ 10侧表示候选除数。

这里是查询中的第一个错误:<必须更改为<=,否则素数平方的平方根将包含在输出中。

CCD_ 13将潜在素数及其候选除数分组为单个组。HAVING子句丢弃所有具有一个或多个候选除数的项,这些除数平均地划分候选素数,即其中MIN(a.n % b.n)为零。

这是需要第二个修正的地方,因为素数3的平方根小于列表中最小的候选除数2。因此,3最终根本没有候选除数,并被HAVING子句抛出;您需要添加UNION ALL0来保存它。

最新更新