繁体   English   中英

使用 group by 和 have 子句

[英]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. 获取供应给至少两个不同项目的零件的供应商编号和名称。

  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 

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;

这个查询的评估可以看作是以下步骤:

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

您可以将其扩展到任何复杂的查询,表可以是任何返回表的复杂查询(叉积、联接、联合等)。

事实上,拥有只是语法糖,并没有扩展 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 ,这是您最初想要的。

您的问题的最佳解决方案

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

  1. 您只需按 Supplies (sid、pid、jid**、quantity) 分组即可找到至少供应两个项目的那些的 sid。
  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 中出现了子句来解决这个问题。 请参阅让子句通过此链接的示例

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

首先,您应该使用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. 获取至少提供给两个不同项目的零件供应商的供应商编号和名称。

  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 

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM