SQLパズル:素数を求める(別解)

 「SQLで数学パズルを解く(数論編)」素数を求める問題について、泉さんという方からメールでうまい別解を教えていただいたので、紹介します(オリジナルに少し私の方で手を加えました)。


SELECT Dividend.num as prime
FROM Numbers Dividend, Numbers Divisor
WHERE 1 < Dividend.num
AND Divisor.num <= SQRT(Dividend.num) --約数は被除数の平方根以下
GROUP BY Dividend.num
HAVING SUM(CASE WHEN MOD(Dividend.num, Divisor.num) = 0
THEN 1
ELSE 0 END) = 1 --1でしか割り切れない
ORDER BY prime;

 SQRT関数が使えない場合は、「Divisor.num <= SQRT(Dividend.num)」は、「Divisor.num <= Dividend.num / Divisor.num」と書いても同じです。「Divisor.num * Divisor.num <= Dividend.num」と書いたほうが素直ですが、この書き方をする場合は、主キーのインデックスを利用するために左辺を裸にするのがいいでしょう。いまnum列に0は含まれないと仮定して構わないので、ゼロ割を考慮する必要はありません。

 HAVING句のMOD関数は、Divisor.numで割り切れれば1、割り切れなければ0を返す特性関数です。この合計が1になるということは、つまり割り切れる数が一つしかなかったということ。そしてDivisor.numには必ず1が含まれるので、これは結局「1でしか割り切れなかった」ということです。

 私の考えたHAVING句の解法よりずっと意味を明確に伝える点が優れた解法です。しかも、約数の検索範囲もSQRT(num)以下に制限できるのでパフォーマンスも向上します。べりぎゅー。