拥有的语义
为了更好地理解拥有,你需要从理论的角度来看待它。
group by是一个查询,它获取一个表并将其汇总到另一个表中。您可以通过将原始表分组为子集(基于您在分组依据中指定的属性)来汇总原始表。这些组中的每一个都将产生一个元组。
Have等同于在group by 执行之后和查询的 select 部分计算之前的WHERE子句。
假设您的查询是:
select a, b, count(*)
from Table
where c > 100
group by a, b
having count(*) > 10;
该查询的评估可以看作是以下步骤:
- 执行 WHERE,消除不满足它的行。
- 根据 a 和 b 的值将表分组为子集(每个子集中的每个元组都具有相同的 a 和 b 值)。
- 消除不满足 HAVING 条件的子集
- 处理每个输出值的子集,如查询的 SELECT 部分所示。这会在步骤 3 之后为每个子集创建一个输出元组。
您可以将其扩展到任何复杂的查询,那里的表可以是任何返回表的复杂查询(叉积、连接、UNION 等)。
事实上,have是语法糖,并没有扩展 SQL 的功能。任何给定的查询:
SELECT list
FROM table
GROUP BY attrList
HAVING condition;
可以改写为:
SELECT list from (
SELECT listatt
FROM table
GROUP BY attrList) as Name
WHERE condition;
listatt 是一个包含 GROUP BY 属性以及列表和条件中使用的表达式的列表。可能需要在此列表中命名一些表达式(使用 AS)。例如,上面的示例查询可以重写为:
select a, b, count
from (select a, b, count(*) as count
from Table
where c > 100
group by a, b) as someName
where count > 10;
您需要的解决方案
您的解决方案似乎是正确的:
SELECT s.sid, s.name
FROM Supplier s, Supplies su, Project pr
WHERE s.sid = su.sid AND su.jid = pr.jid
GROUP BY s.sid, s.name
HAVING COUNT (DISTINCT pr.jid) >= 2
你把三张表连接起来,然后用sid作为分组属性(sname在功能上是依赖它的,所以对组数没有影响,但是一定要包含,否则不能成为select部分的一部分该声明)。然后,您将删除那些不满足您的条件的:满足pr.jid is >= 2
,这是您最初想要的。
您问题的最佳解决方案
我个人更喜欢更简单的清洁解决方案:
- 您只需按供应品(sid、pid、jid**、数量)进行分组,即可找到至少为两个项目供应的供应品的 sid。
- 然后将其加入供应商表以获取相同的供应商。
SELECT sid, sname from
(SELECT sid from supplies
GROUP BY sid
HAVING count(DISTINCT jid) >= 2
) AS T1
NATURAL JOIN
Supliers;
执行起来也会更快,因为仅在需要时才进行连接,而不是一直进行。
--dmg