1、设有如图3所示的三个关系。其中各个属性的含义如下:A#(商店代号)、ANAME(商店名)、WQTY(店员人数)、CITY(所在城市)、B#(商品号)、BNAME(商品名称)、PRICE(价格)、QTY(商品数量)。
(2)找出至少供应了代号为’256’的商店所供应的全部商品的其它商店的商店名和所在城市。
(2)SELECT ANAME,CITY FROM A
WHERE NOT EXISTS
(SELECT * FROM B
WHERE EXISTS
(SELECT * FROM AB AB1
WHERE A#='256' AND B#=#)
AND NOT EXISTS
(SELECT * FROM AB AB2
WHERE A#!='256' AND A#=# AND B#=#)
); (4分)
可以详细讲解一下这个第二小问吗
1、原SQL补全(我使用的是 t_a、t_b及t_ab表,应对原来的 A 、B、AB表):
SELECT ANAME, CITY
FROM t_a a
WHERE NOT EXISTS( SELECT *
FROM t_b b
WHERE EXISTS( SELECT * FROM t_ab c WHERE c.aid = '256' AND c.bid = b.bid )
AND NOT EXISTS( SELECT * FROM t_ab d WHERE d.aid != '256' AND d.aid = a.aid AND d.bid = b.bid ) );
其执行逻辑思路大致为:
①、针对表 t_a 的每一个(行)商店信息(假设为商店X)进行如下【不存在】性判定:
②、提取所有商店“256”的供应商品(EXISTS子句)中,商店X的供应商品中不存在的商品(最后一个 NOT EXISTS 子句)列表
③、第 ② 中存在商品列表数据,则 商店X 不满足,被过滤掉,否则就算满足,输出到最终结果集中(最外层 NOT EXISTS 子句)
2、除上述比较烧脑的组合NOT EXISTS方式外,也可以使用 @变量(MySQL 8 则直接使用count() over())直接关联的方式:
SELECT aname, city
FROM t_a m JOIN ( SELECT b.aid -- a.aid, a.bid, @cnt AS cnt, b.aid, b.bid
FROM ( SELECT aid, bid, @cnt := @cnt + 1 AS cnt FROM t_ab, ( SELECT @cnt := 0 ) k WHERE aid = '256' ) a JOIN ( SELECT aid, bid FROM t_ab WHERE aid != '256' ) b ON a.bid = b.bid
GROUP BY b.aid
HAVING count( 1 ) = @cnt ) n ON m.aid = n.aid;
大致思路为:
①、提取商店256的所有商品并计数(@变量的作用就是统计商品总数)(子查询 a )
②、然后关联所有其他非商店256的商店提供商品(子查询b)中提取与商店256供应同样商品的商品列表
③、接着以商店为目标进行分组统计,统计每个商店与商店256提供同种商品的总数量(GROUP BY)
④、然后过渡出总数量与商店256供应商品总数据相同的商店(HAVING 子句)
⑤、最后关联 t_a 商店表,提取目标商店名和所在城市信息并输出
上述两个SQL涉及测试数据:
t_a:
t_b:
t_ab:
两个SQL的输出结果(相同):