使用group by和having子句

use*_*124 39 sql

使用以下架构:

Supplier (sid, name, status, city)
Part (pid, name, color, weight, city)
Project (jid, name, city)
Supplies (sid, pid, jid**, quantity)
Run Code Online (Sandbox Code Playgroud)
  1. 获取供应给至少两个不同项目的零件供应商的供应商编号和名称.

  2. 为至少两个不同的项目获取同一部件供应商的供应商编号和名称.

这些是我的答案:

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 
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

任何人都可以确认我是否写得正确吗?关于Group By和Having子句如何工作,我有点困惑

dmg*_*dmg 93

拥有的语义

为了更好地理解,你需要从理论的角度来看待它.

按组是一个查询,需要一个表,并将其汇总成另一个表.通过将原始表分组为子集(基于您在组中指定的属性)来汇总原始表.这些组中的每一组都将产生一个元组.

是简单地等同于WHERE子句的组通过已执行,并且之前选择查询的一部分进行计算.

让我们说你的查询是:

select a, b, count(*) 
from Table 
where c > 100 
group by a, b 
having count(*) > 10;
Run Code Online (Sandbox Code Playgroud)

对此查询的评估可以看作以下步骤:

  1. 执行WHERE,消除不满足它的行.
  2. 基于a和b的值将表分组为子集(每个子集中的每个元组具有相同的a和b值).
  3. 消除不满足HAVING条件的子集
  4. 处理输出值的每个子集,如查询的SELECT部分​​所示.这会在步骤3之后创建每个子集一个输出元组.

您可以将其扩展到任何复杂查询,Table可以是任何返回表的复杂查询(交叉产品,连接,UNION等).

事实上,语法糖,并且不扩展SQL的力量.任何给定的查询:

SELECT list 
FROM table
GROUP BY attrList
HAVING condition;
Run Code Online (Sandbox Code Playgroud)

可以改写为:

SELECT list from (
   SELECT listatt 
   FROM table 
   GROUP BY attrList) as Name
WHERE condition;
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

您需要的解决方案

您的解决方案似乎是正确的:

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 
Run Code Online (Sandbox Code Playgroud)

你加入了三个表,然后使用SID为分组属性(SNAME函数依赖于它,所以它不会对组的数量产生影响,但你必须包括它,否则就不能成为选择部分的一部分该声明).然后你将删除那些不满足你条件的东西:满足pr.jid is >= 2,这是你原本想要的.

解决您问题的最佳方案

我个人更喜欢更简单的清洁解决方案:

  1. 您只需按供应(sid,pid,jid**,数量)进行分组,即可找到至少供应两个项目的供应商的sid.
  2. 然后将其加入供应商表以使供应商获得相同的信息.

 SELECT sid, sname from
    (SELECT sid from supplies 
    GROUP BY sid, pid 
    HAVING count(DISTINCT jid) >= 2
    ) AS T1
NATURAL JOIN 
Supliers;
Run Code Online (Sandbox Code Playgroud)

它的执行速度也会更快,因为连接只在需要时完成,而不是所有时间.

--dmg


小智 5

因为我们不能使用具有聚合函数的 Where子句,如count(),min(),sum()等等.所以有了一个子句来克服sql中的这个问题.请参阅有关子句的示例通过此链接

http://www.sqlfundamental.com/having-clause.php

  • 有另一个链接?那一个破了:( (4认同)

cbp*_*cbp 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
Run Code Online (Sandbox Code Playgroud)

与尝试使用 GROUP BY 相比,它更具可读性,也更省心。但性能可能会有所不同。