[英]Using group by and having clause
使用以下架构:
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 和 Have 子句的工作方式有些困惑
拥有的语义
为了更好地理解拥有,你需要从理论的角度来看待它。
group by是一个查询,它获取一个表并将其汇总到另一个表中。 您可以通过将原始表分组为子集来汇总原始表(基于您在分组依据中指定的属性)。 这些组中的每一个都将产生一个元组。
在HAVING是简单地等同于WHERE子句的组由已执行,并且查询的选择部分被计算之前后。
假设您的查询是:
select a, b, count(*)
from Table
where c > 100
group by a, b
having count(*) > 10;
这个查询的评估可以看作是以下步骤:
您可以将其扩展到任何复杂的查询,表可以是任何返回表的复杂查询(叉积、联接、联合等)。
事实上,拥有只是语法糖,并没有扩展 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
你join这三个表,然后使用sid作为分组属性(sname在功能上依赖于它,所以它对组数没有影响,但是你必须包含它,否则它不能成为select部分的一部分该声明)。 然后您将删除那些不满足您的条件的:满足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
因为我们不能将 Where 子句与count()、min()、sum()等聚合函数一起使用,所以在 sql 中出现了子句来解决这个问题。 请参阅让子句通过此链接的示例
首先,您应该使用JOIN
语法而不是FROM table1, table2
,并且您应该始终将分组限制为您需要的尽可能少的字段。
我还没有测试过,你的第一个查询对我来说似乎很好,但可以重写为:
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
使用什么类型的 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 相比,它更具可读性,也更容易让人费解。 性能可能有所不同。
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)
我不太清楚你的第二个问题
使用以下架构:
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 and Haveing子句的工作方式有些困惑
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.