原创: 牛超 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,通过构造集合,将数据组合转换为表连接,将推理过程转化为分析查询与过滤筛选,即可解决该类问题。