Oracle的SQL语句功能还是很强的,看到两道比较有趣的题,用SQL来尝试求解。
第二个问题:
Gauss和Poincare在天堂相遇了,上帝说:你们都是人间最伟大的数学家,那我来出道题考考你们谁更聪明。我在左手写一个大于1小于100的数,在右手同样写一个大于1小于100的数,然后把他们的和写在Gauss手上,把积写在Poincare手上,看看你们能不能猜出这两个数字是几。
Gauss看了手上的数字,说:“我不知道这两个数字是几,可我保证Poincare也不知道。”
Poincare看了手上的数字,说:“我原来的确不知道那两个数字是几,可我现在知道了。”
Gauss说:“那我也知道了。”问题:那两个数字是几?
粗看上去似乎和刚才第一题很像,如果仔细研究就会发现二者的区别还是很大的,相比之下,这道题比第一题要难一些。
仍然是先给出SQL解,然后描述一下思路:
SQL> WITH T_NUM AS
2 (SELECT ROWNUM + 1 NUM FROM DUAL CONNECT BY LEVEL < 99)
3 SELECT A, B
4 FROM
5 (
6 SELECT
7 A,
8 B,
9 TOTAL,
10 MUL,
11 MUL_P,
12 COUNT(DECODE(MUL_P, 1, 1)) OVER(PARTITION BY TOTAL) VALUE
13 FROM
14 (
15 SELECT
16 A,
17 B,
18 TOTAL,
19 MUL,
20 COUNT() OVER (PARTITION BY TOTAL) TOTAL_P,
21 COUNT() OVER (PARTITION BY MUL) MUL_P
22 FROM
23 (
24 SELECT
25 A,
26 B,
27 TOTAL,
28 MUL,
29 MIN(MUL_P) OVER (PARTITION BY TOTAL) MUL_M
30 FROM
31 (
32 SELECT
33 A.NUM A,
34 B.NUM B,
35 A.NUM + B.NUM TOTAL,
36 A.NUM * B.NUM MUL,
37 COUNT() OVER (PARTITION BY A.NUM + B.NUM) TOTAL_P,
38 COUNT() OVER (PARTITION BY A.NUM * B.NUM) MUL_P
39 FROM T_NUM A, T_NUM B
40 WHERE A.NUM < B.NUM
41 )
42 )
43 WHERE MUL_M != 1
44 )
45 )
46 WHERE MUL_P = 1
47 AND VALUE = 1;
A B
4 13
下面简单描述一下思路:
WITH语句就是构造一张基础数据表。
最内层的循环构造两个数的笛卡儿积,列出所有的可能,不过对于我们来说,A取1,B取2和A取2,B取1没有区别,因此加上限制条件A > B。循环中的分析函数用来计算A、B两个数的和相同的个数以及A、B两个数的积相同的个数。
下面到了这道题和第一题的区别之处。Gauss不但自己不知道,还可以确认Poincare也不知道。这说明A、B两个数构成Gauss手里的和TATOL不但不是唯一的,而且所有能构成这个TOTAL的A和B的积MUL都不是唯一的。这就是第二层嵌套的含义。
到了第三层,过滤掉上面那些不符合条件的A和B之后。要解决的问题就是Poincare知道A和B的答案后,Gauss也知道了。
这说明对于TOTAL这个值,所有A和B的组合中有一个且只有一个组合它们的乘积是唯一确定的。这是通过第四层嵌套中那个COUNT(DECODE) OVER实现的。
最后过滤乘积唯一,且对于相同TOTAL的所有A和B组合中有且仅有一个乘积唯一确定的A、B组合。
如果还是不明白,可以将这个嵌套一层层执行,观察每一步的执行结果,有助于理解每一步实现的目的。