在SQL中练习WHERE和HAVING

时间:2010-03-10 04:50:40

标签: sql

这是架构:

alt text http://img30.imageshack.us/img30/3324/123vk.jpg

这是一个问题:

指出来自同一国家的至少三艘船参加的战斗。

这是我的回答:

  SELECT battles.name 
    FROM battles,
         outcomes,
         ships,
         classes 
   WHERE outcomes.ship = ships.name 
GROUP BY battles.name 
  HAVING COUNT(classes.country) >= 3;

你能告诉我为什么这是错的,并帮我纠正它!

8 个答案:

答案 0 :(得分:5)

此:

SELECT battles.name 
  FROM battles,
       outcomes,
       ships,
       classes 
 WHERE outcomes.ship = ships.name 

...从根本上存在缺陷,因为OUTCOMESSHIPS之间只有加入条件。结果是笛卡尔积。它是有效的 ANSI-89语法,但不会返回类似于您期望的结果集。

如果你只想要战斗“名字”,请使用:

  SELECT o.battle
    FROM OUTCOMES o
    JOIN SHIPS s ON s.name = o.ship
    JOIN CLASSES c ON c.class = s.class
GROUP BY o.battle
  HAVING COUNT(c.country) >= 3

如果您想要战斗表详细信息,请使用:

SELECT b.*
 FROM BATTLES b
 JOIN (SELECT o.battle
         FROM OUTCOMES o
         JOIN SHIPS s ON s.name = o.ship
         JOIN CLASSES c ON c.class = s.class
     GROUP BY o.battle
       HAVING COUNT(c.country) >= 3) x ON x.battle = b.name

答案 1 :(得分:4)

SELECT DISTINCT BattleName
FROM (
   SELECT Battles.name AS BattleName, Class.Country, COUNT(*)
   FROM Battles
   JOIN Outcomes ON battles.name = Outcomes.battle 
   JOIN Ships ON Outcomes.ship = Ships.name
   JOIN Classes ON Ships.class = Class.class
   GROUP BY battles.name, Classes.country 
   HAVING COUNT(*) >= 3;
)

原始查询中的主要缺陷是表格之间的连接没有表达,导致了普通的笛卡尔积。

另一个问题是该国家/地区未列入允许按国家计算船舶的情况。然后将此修改后的查询作为子查询,以允许仅选择一次BattleName。

注意:
  - 我在SELECT列表中添加了COUNT(*)。这更多是出于安全/无知,我认为某些SQL实现需要在HAVING子句中找到的聚合值存在于SELECT列表中。 (我可能错了)   - 而不是COUNT(*)可能需要使用说COUNT(Classes.country)或任何其他字段(如果出现此MS-Access,则可能不允许使用COUNT(*)语法。)

答案 2 :(得分:1)

 SELECT 
   battles.name 
 FROM battles,
      outcomes,
      ships,
      classes 
 WHERE battles.name=outcome.battle 
 AND   outcomes.ship = ships.name 
 AND   ships.class=classes.class
 GROUP BY battles.name
 HAVING COUNT(classes.country) >= 3;

答案 3 :(得分:1)

select distinct A.battle
from
(select country, o.battle from outcomes o
left join ships s
on s.name = o.ship
left join classes c 
on c.class = s.class  
group by o.battle, country
having count(country) >= 3) A

答案 4 :(得分:0)

我从未使用过GROUP BY语句的HAVING子句。但是,GROUP BY应仅用于聚合目的。因此,如果您没有选择agregation函数(SUM,MAX,MIN,AVG,COUNT等),您将无法进行GROUP BY。

答案 5 :(得分:0)

你搞砸了桌子上的连接。您不能只列出表格,您必须指定它们如何连接在一起

From Battles
Inner Join Outcomes On Outcomes.Battle = Battles.name
Inner Join Ships.Name On Ship.Name = Outcomes.Ship
Inner Join Classes.Class = Ship.Class

答案 6 :(得分:0)

我看不到你的形象(由大哥过滤掉)

但是,请记住,WHERE首先过滤整个行,GROUP BY合并剩余的行,Having过滤这些行。

FROM& JOIN确定&过滤行 WHERE行上的更多过滤器
GROUP BY将这些行组合成组 HAVING过滤群组 ORDER BY安排剩余的行/组

答案 7 :(得分:0)

scrollHeight

这将解决您的问题。