使用以下架构:
Supplier (sid, name, status, city)
Part (pid, name, color, weight, city)
Project (jid, name, city)
Supplies (sid, pid, jid**, quantity)
获取供应给至少两个不同项目的零件供应商的供应商编号和名称。
为至少两个不同的项目获取同一部件供应商的供应商编号和名称。
这些是我的答案:
1
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
2
SELECT s.sid, s.name
FROM Suppliers s, Supplies su, Project pr, Part p
WHERE s.sid = su.sid AND su.pid = p.pid AND su.jid = pr.jid
GROUP BY s.sid, s.name
HAVING COUNT (DISTINCT pr.jid)>=2
任何人都可以确认我是否写得正确吗?关于Group By和Having子句如何工作,我有点困惑
答案 0 :(得分:92)
拥有
的语义为了更好地理解,你需要从理论的角度来看待它。
group by 是一个查询,它接受一个表并将其汇总到另一个表中。通过将原始表分组为子集(基于您在组中指定的属性)来汇总原始表。每个组都会产生一个元组。
拥有只是等同于分组后的WHERE子句已执行并且在计算查询的 select 部分之前。
让我们说你的疑问是:
select a, b, count(*)
from Table
where c > 100
group by a, b
having count(*) > 10;
此查询的评估可以看作以下步骤:
您可以将此扩展到任何复杂查询。表可以是任何返回表的复杂查询(交叉产品,连接,UNION等)。
事实上, 是syntactic sugar,并没有扩展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属性以及list和condition中使用的表达式。可能需要在此列表中命名一些表达式(使用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在功能上依赖于它,因此它对组的数量没有影响,但必须包含它,否则它不能成为声明选择部分的一部分)。然后你将删除不满足你条件的那些:满足pr.jid is >= 2
,这是你原来想要的。
解决您问题的最佳方案
我个人更喜欢更简单的清洁解决方案:
SELECT sid, sname from
(SELECT sid from supplies
GROUP BY sid, pid
HAVING count(DISTINCT jid) >= 2
) AS T1
NATURAL JOIN
Supliers;
执行起来也会更快,因为连接只在需要时完成,而不是所有时间。
- DMG
答案 1 :(得分:5)
因为我们不能使用聚合函数的Where子句,如 count(),min(),sum()等所以有条款来克服这个sql中的问题。请参阅有关子句的示例通过此链接
答案 2 :(得分:1)
首先,您应该使用JOIN
语法而不是FROM table1, table2
,并且应始终将分组限制为您需要的字段。
Altought我没有测试过,你的第一个查询对我来说似乎很好,但可以重写为:
SELECT s.sid, s.name
FROM
Supplier s
INNER JOIN (
SELECT su.sid
FROM Supplies su
GROUP BY su.sid
HAVING COUNT(DISTINCT su.jid) > 1
) g
ON g.sid = s.sid
或简化为:
SELECT sid, name
FROM Supplier s
WHERE (
SELECT COUNT(DISTINCT su.jid)
FROM Supplies su
WHERE su.sid = s.sid
) > 1
但是,您的第二个查询对我来说似乎不对,因为您还应该GROUP BY pid
。
SELECT s.sid, s.name
FROM
Supplier s
INNER JOIN (
SELECT su.sid
FROM Supplies su
GROUP BY su.sid, su.pid
HAVING COUNT(DISTINCT su.jid) > 1
) g
ON g.sid = s.sid
正如您在上面的查询中所注意到的,我使用INNER JOIN
语法来执行过滤,但它也可以写为:
SELECT s.sid, s.name
FROM Supplier s
WHERE (
SELECT COUNT(DISTINCT su.jid)
FROM Supplies su
WHERE su.sid = s.sid
GROUP BY su.sid, su.pid
) > 1
答案 3 :(得分:0)
使用什么类型的sql数据库(MSSQL,Oracle等)? 我相信你所写的是正确的。
您也可以像这样编写第一个查询:
SELECT s.sid, s.name
FROM Supplier s
WHERE (SELECT COUNT(DISTINCT pr.jid)
FROM Supplies su, Projects pr
WHERE su.sid = s.sid
AND pr.jid = su.jid) >= 2
与使用GROUP BY进行操作相比,它更具可读性,并且不那么令人费解。但性能可能会有所不同。
答案 4 :(得分:0)
1.获取供应给至少两个不同项目的零件供应商的供应商编号和名称。
SELECT S.SID, S.NAME
FROM SUPPLIES SP
JOIN SUPPLIER S
ON SP.SID = S.SID
WHERE PID IN
(SELECT PID FROM SUPPPLIES GROUP BY PID, JID HAVING COUNT(*) >= 2)
我对你的第二个问题并不感兴趣
答案 5 :(得分:0)
Having:它对每组行应用过滤条件。 其中:它应用单个行的过滤器。