用SQL解决两道有趣的题(一)

Oracle的SQL语句功能还是很强的,看到两道比较有趣的题,用SQL来尝试求解。

第一个问题:
已知两个1~30之间的数字,甲知道两数之和,乙知道两数之积。
甲问乙:"你知道是哪两个数吗?"乙说:“不知道”;
乙问甲:"你知道是哪两个数吗?"甲说:“也不知道”;
于是,乙说:“那我知道了”;
随后甲也说:“那我也知道了”;
这两个数是什么?
先给出SQL解,然后简单描述一下。
这道题分两种情况,两个数不重复,那么有两个可能结果:
SQL> WITH
2 T AS
3 (SELECT ROWNUM NUM FROM DUAL CONNECT BY LEVEL <= 30)
4 SELECT A, B
5 FROM
6 (
7 SELECT
8 A,
9 B,
10 TOTAL,
11 MUL,
12 COUNT() OVER (PARTITION BY MUL) MUL_P
13 FROM
14 (
15 SELECT
16 A,
17 B,
18 TOTAL,
19 MUL,
20 COUNT(
) OVER (PARTITION BY TOTAL) TOTAL_P
21 FROM
22 (
23 SELECT
24 A.NUM A,
25 B.NUM B,
26 A.NUM + B.NUM TOTAL,
27 A.NUM * B.NUM MUL,
28 COUNT(*) OVER (PARTITION BY A.NUM * B.NUM) MUL_P
29 FROM T A, T B
30 WHERE A.NUM < B.NUM
31 )
32 WHERE MUL_P != 1
33 )
34 WHERE TOTAL_P != 1
35 )
36 WHERE MUL_P = 1
37 ;
A B


1 6
1 8
如果两个数是可以重复的,那么有唯一的答案:
SQL> WITH
2 T AS
3 (SELECT ROWNUM NUM FROM DUAL CONNECT BY LEVEL <= 30)
4 SELECT A, B
5 FROM
6 (
7 SELECT
8 A,
9 B,
10 TOTAL,
11 MUL,
12 COUNT() OVER (PARTITION BY MUL) MUL_P
13 FROM
14 (
15 SELECT
16 A,
17 B,
18 TOTAL,
19 MUL,
20 COUNT(
) OVER (PARTITION BY TOTAL) TOTAL_P
21 FROM
22 (
23 SELECT
24 A.NUM A,
25 B.NUM B,
26 A.NUM + B.NUM TOTAL,
27 A.NUM * B.NUM MUL,
28 COUNT(*) OVER (PARTITION BY A.NUM * B.NUM) MUL_P
29 FROM T A, T B
30 WHERE A.NUM <= B.NUM
31 )
32 WHERE MUL_P != 1
33 )
34 WHERE TOTAL_P != 1
35 )
36 WHERE MUL_P = 1
37 ;
A B


1 4
下面简单描述一下思路:
WITH语句就是构造一张基础数据表。
最内层的循环构造两个数的笛卡儿积,列出所有的可能,不过对于我们来说,A取1,B取2和A取2,B取1没有区别,因此加上限制条件A > B。上面两个SQL唯一的区别就在这里,如果两个数是可以重复的那么A >= B,否则A > B。
循环中的分析函数用来计算A和B乘积相同的个数,如果这个数是1,说明这两个数是可以确定的。而根据乙的描述,他并不知道这两个数是什么,因此这部分应该是可以被排除的。
第二层的循环道理相同,这里排除的是A所不知道的,两个数和能确定这两个数的部分。
到了第三层,乙知道A和B是什么数了,说明这个时候A和B的积已经是唯一的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值