Thinking in SQL系列之二:鬼谷子问徒

原创: 牛超   2017-02-09   Mail:[email protected]

前几天看过杨长老的一篇文章,是关于SQL进行逻辑推理的,感觉很有新意。

当时只是粗略地看了一下思路,藉着这篇博文我再重新梳理一下。

百度到题目的出处:鬼谷子问徒是一道古老的广为流传的经典逻辑推理题目。具体问题是这样的:

一天,鬼谷子随意从2-99中选取了两个数。他把这两个数的和告诉了庞涓,把这两个数的乘积告诉了孙膑,但孙膑和庞涓彼此不知到对方得到的数。 
第二天,庞涓很有自信的对孙膑说:虽然我不知到这两个数是什么,但我知道你一定也不知道。 
随后,孙膑说:本来我不知道,现在知道了,庞涓随后说:那我也知道了

请问这两个数字是什么?

这种问题感觉需要写几层循环以及排除质数的算法,可以用一个SQL来解决吗?

答案是肯定的,SQL有着独特的解决问题的方式,即层次查询与分析函数,

同样,构造集合是关键,以下脚本注明了逐层的推理步骤:

WITH TA AS (--构造2-99集合
SELECT ROWNUM + 1 RNUM 
FROM DUAL 
CONNECT BY ROWNUM < 99
) ,
TB AS (--鬼谷子随意从2-99中选取了两个数
SELECT A.RNUM NA ,B.RNUM NB,
A.RNUM + B.RNUM SUMAB,--他把这两个数的和告诉了庞涓
A.RNUM * B.RNUM PROAB,--把这两个数的乘积告诉了孙膑
COUNT(1) OVER (PARTITION BY A.RNUM + B.RNUM ) SUMCNT1, --同和个数
COUNT(1) OVER (PARTITION BY A.RNUM * B.RNUM ) PROCNT1  --同积个数
FROM TA A 
JOIN TA B
ON A.RNUM <= B.RNUM 
)  ,
TC AS (
SELECT TB.*,
COUNT(1) OVER (PARTITION BY SUMAB) SUMCNT2,
COUNT(1) OVER (PARTITION BY PROAB) PROCNT2 
FROM TB
WHERE SUMCNT1 > 1 --庞涓不知道两数是什么--
) ,
TD AS (
SELECT TC.*,
MIN(PROCNT2) OVER (PARTITION BY SUMAB) PROCNT3 --和相同两数的积的最小个数
FROM TC
), 
TE AS (
SELECT TD.*,
COUNT(1) OVER (PARTITION BY PROAB) PROCNT4
FROM TD
WHERE PROCNT3 > 1 --庞涓很有自信的对孙膑说:虽然我不知到这两个数是什么,但我知道你一定也不知道
) ,
TF AS (
SELECT TE.*,
COUNT(1) OVER (PARTITION BY SUMAB) SUMCNT5
FROM TE
WHERE PROCNT1 > 1 --孙膑说:本来我不知道
AND PROCNT4 = 1 --现在知道了
)
SELECT *
FROM TF
WHERE SUMCNT5 = 1 ;--庞涓随后说:那我也知道了

输出NA为4,NB为13便是鬼谷子选出的两个数字

可以看出,脚本很短,无需循环处理,Thinking in SQL,通过构造集合,将数据组合转换为表连接,将推理过程转化为分析查询与过滤筛选,即可解决该类问题。

点赞