您的位置:首页 > 数据库

实例分析SQL中除法的三种写法

2009-12-27 20:30 323 查看
首先请看

http://topic.csdn.net/u/20070821/15/8a2dac05-51b8-4eb1-b41d-4fbe8a232c85.html

帖中从实际问题出发,讨论SQL语句中如何表示除法运算。

以下是问题的给出与简要描述:

表A:商店信息
ANO,   ANAME,   WQTY,   CITY
101,   韶山书店,   15,   长沙
204,   前门商店,   89,   北京
256,   东风商场,   501,   北京
345,   铁道商店,   76,   长沙
620,   武汉商场,   413,   武汉

表B:商品信息
BNO,   BNAME,   PRICE
1,   毛笔,   21
2,   羽毛球,   4
3,   收音机,   325
4,   书包,   242

表AB:商店-商品对应关系
ANO,   BNO,   QTY
101,   1,   105
101,   2,   42
101,   3,   25
101,   4,   104
204,   3,   61
256,   1,   241
256,   2,   91
345,   1,   141
345,   2,   18
345,   4,   74
620,   4,   125

现在要找出至少供应代号为256的商店所供应的全部商品的商店代号ANO,只涉及到表AB。这个SQL语句该怎么写?

具体说,我已经知道关系表达式是:
π   ano,   bno   (AB)   ÷   π   bno   (σ   ano   =   256   (AB));

我的问题是:如何把这里的除法运算转化为SQL语句呢?


然后下面有很多的回答,在这里我就不一一列出了。

先给出我的测试DDL与SQL语句。

--DDL:

CREATE TABLE AB(
ANO INT,
BNO INT,
QTY INT
);

INSERT INTO AB VALUES ( 101,   1,   105 );
INSERT INTO AB VALUES ( 101,   2,   42 );
INSERT INTO AB VALUES ( 101,   3,   25 );
INSERT INTO AB VALUES ( 101,   4,   104 );
INSERT INTO AB VALUES ( 204,   3,   61 );
INSERT INTO AB VALUES ( 256,   1,   241 );
INSERT INTO AB VALUES ( 256,   2,   91 );
INSERT INTO AB VALUES ( 345,   1,   141 );
INSERT INTO AB VALUES ( 345,   2,   18 );
INSERT INTO AB VALUES ( 345,   4,   74 );
INSERT INTO AB VALUES ( 620,   4,   125 );

--SQL:

--1、正统做法:

SELECT DISTINCT ANO FROM AB
WHERE ANO NOT IN (
SELECT ANO FROM (
SELECT ANO,BNO FROM (
SELECT ANO FROM AB
) AS r1 CROSS JOIN (
SELECT BNO FROM AB
WHERE ANO = 256
) AS s1
) AS rs1
WHERE CHECKSUM(ANO,BNO) NOT IN (
SELECT CHECKSUM(ANO,BNO) FROM AB
)
);

--2、我的一位同学想出来的解法,想法非常好:

SELECT ANO FROM (
SELECT ANO FROM AB
WHERE BNO IN (
SELECT BNO FROM AB
WHERE ANO = 256
)
) AS rs1
GROUP BY ANO
HAVING COUNT(ANO) = (
SELECT COUNT(*) FROM AB
WHERE ANO = 256
);

--3、第二天早上想到的方法,就是传说中的双NOT EXISTS方法,应该是结构最直观的方法了。
SELECT DISTINCT ANO FROM AB AS AB1
WHERE NOT EXISTS (
SELECT 1 FROM AB AS AB2
WHERE ANO = 256
AND NOT EXISTS (
SELECT 1 FROM AB AS AB3
WHERE AB3.BNO = AB2.BNO
AND AB3.ANO = AB1.ANO
)
);


解法一:

解法一使用的是《数据库系统概念(第五版)》上给出的正统转换方法:

r ¸ s = { t | t Î Õ R-S(r) Ù " u Î s ( tu Î r ) }

r ¸ s = ÕR-S (r) –ÕR-S ( (ÕR-S (r) x s) – ÕR-S,S(r))

我在这里做的就是把这段关系表达式转换成SQL语句就可以了。

在这里稍微解释一下这个关系表达式的由来。

整体思路就是先选出r集合中的(R-S)*(1)属性,然后与s集合进行笛卡尔操作,这时候得到的是(ÕR-S (r) x s) ,就是r集合中全部元组都能被选出来的理想情况*(2)(姑且这么说);然后减去集合r中的现实情况*(3)ÕR-S,S(r))(表示集合r属性的重新排列:而属性重新排列是集合进行差集运算所要求的),得到现实与理想的“差距”,并选出(R-S)的属性,就得到ÕR-S ( (ÕR-S (r) x s) – ÕR-S,S(r))。最后再用ÕR-S (r)(实际的集合)来与刚刚得出的ÕR-S ( (ÕR-S (r) x s) – ÕR-S,S(r))进行差集运算,得出符合理想(规定)的那些元组——而这些元组就是r ¸ s的结果了。

注:(1) (R-S)属性指的是r集合与s集合的关系模式的差集(即r集合中的字段集合与s集合中的字段集合的差集),其中S Í R,这是集
合除法规定的。

(2) 理想情况指的是所有元组都能成功配对的情况(通过笛卡尔积实现)。

(3) 现实情况指的是当前r集合中的实际元组情况。

解法二:

解法二的思路十分地独特,它巧妙地运用group by而大大简化了操作。

整体思路就是①先把r集合中的与s集合的相同字段(模式S)有相同值的元组提取出来(使用IN操作就可以了),②然后再对查询结果以它们相异的字段(模式R-S)分组,然后统计每个分组的COUNT是否等于期望的COUNT值(即s集合中的元组数),符合的就是结果了。

思路就这么简单,大家仔细想想就明白了。

解法三:

解法三就是传说中的双NOT EXISTS做法了,它的思路非常的直观,就是三层SELECT语句的嵌套。

整体思路就是,先求出ANO为256的BNO集合,然后与针对每一个相同ANO的BNO集合进行差集运算,如果结果为空集,那么就证明了该ANO的BNO集合包含了预期的BNO集合(即ANO为256的BNO集合),该集合可被输出,然后继续下一个ANO。

Note that X – Y = Ø Û X Í Y

其实就是以上这条公式的思路。

讲解中可能有不正确的地方,也希望大家可以指出~ ^_^

如果大家还有更多的好的写法,也欢迎大家留下~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: