2016-04-03 56 views
3

有人可以向我解释这个SQL查询是如何工作的吗?这个递归SQL CTE是如何工作的?

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]

UNION ALL - 与来自n < 1000的递归分量n + 1结合,因此显示所有数字从2到1000

SELECT a.n FROM n a - 运行上述查询[CTE的递归构件]

LEFT JOIN n b - 左边与第二组数字

ON b.n < sqrt(a.n)加入号2-1000 - 在所述第二组数字小于第一列数字的平方根?

GROUP BY a.n - 只显示数字

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

这是一个愚蠢的查询,但任何帮助解密它将不胜感激。

+0

我认为这里的意图是生成少于1000的素数。但是,结果似乎并没有证实,因为你得到25,49等 –

+0

仔细观察结果,我认为你的查询生成所有素数并且它们的正方形小于1000.但是你必须在'having'子句中增加一个条件'HAVING = 2或者= 3或者MIN(an%bn)> 0'来在结果中包括3。 –

回答

4

您的查询,当正确固定,生成素数低于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 

Demo.

的解释是相当简单:您查询的递归部分是简单地给你一个方法从2(含)至1000(包括)的数字列表。您可以将递归子句替换为填充了连续整数的实际表。

然后将这些数字输入到您的查询的非CTE部分,并在b.n < sqrt(a.n)的条件下加入自己。 a方代表候选素数; b方代表候选除数。

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

GROUP BY将其候选除数的潜在素数归为一组。 HAVING子句用一个或多个候选除数将所有候选素数均等地分开,即MIN(a.n % b.n)为零。

这是您需要第二次修复的位置,因为质数的3的平方根小于列表上最小的候选除数2。因此,3最终没有候选因子,并被HAVING子句抛出;你需要添加OR a.n=3来保存它。

+0

太棒了!谢谢 – OrdinaryHuman