2

表:

  • Classes (class, type, country, numGuns, bore, displacement)
  • Ships (name, class, launched)
  • Outcome (ship, battle, result)

问题:

为每个等级找出该等级在战斗中沉没的船只数量。

我的答案:

  SELECT ships.class, COUNT(*)
  FROM ships, outcome
  WHERE ships.name = outcomes.ship AND outcome.result = 'sunk'
  GROUP BY ships.class

加入回答:

  SELECT class, COUNT(*)
  from ships
  inner join outcomes
  on name = ship 
  where outcome.result = 'sunk'
  group by class

样本手册中给出的答案:

  SELECT classes.class, COUNT(*)
  FROM classes, ships, outcomes
  WHERE classes.class = ships.class AND ship = name AND result = 'sunk'
  GROUP BY classes.class;

我不明白为什么他们必须包含classes表格,我的查询还不够吗?我正在做同样的事情,但没有加入classes桌子。提前致谢。

4

9 回答 9

2

唯一真正的区别是,如果有一个没有船的班级,则提供的答案将包含一行,而您的查询不会。

糟糕,对不起,我最初误读了示例答案。它们之间没有真正的区别。


还值得注意的是,这种语法:

SELECT classes.class, COUNT(*)
FROM classes, ships, outcomes
WHERE classes.class = ships.class AND ship = name AND result = 'sunk'
GROUP BY classes.class;

过时且已弃用。这是首选的现代语法:

SELECT classes.class, COUNT(*)
FROM classes
INNER JOIN ships    ON classes.class = ships.class
INNER JOIN outcomes ON outcomes.ship = ships.name
WHERE  outcomes.result = 'sunk'
GROUP BY classes.class;
于 2013-03-10T18:19:18.320 回答
2

最简单的答案...

SELECT class,
SUM(CASE WHEN result='sunk' THEN 1 ELSE 0 END) 
FROM
(
    SELECT class, ship, result 
    FROM Classes c 
    LEFT JOIN Outcomes o 
    ON o.ship=c.class
UNION
    SELECT class, ship, result
    FROM Ships s 
    LEFT JOIN  Outcomes o 
    ON o.ship=s.class OR o.ship=s.name
)
AS res
GROUP BY class
于 2016-09-18T11:02:30.873 回答
2

对于每个类,此查询将返回沉没的船的数量,因此如果没有船沉没,您的计数将为 0,而不是仅显示具有计数的船沉没的类。

select class, count(ship) as Sunk_Count
from ships left outer join
(select outcomes.ship
from Outcomes
where result = 'Sunk') as result
on Ships.name = result.ship
group by class

这是输出的样子

| ID | Class     | Sunk_Count |
| 1  | Kongo     |  1         | 
| 2  | Renown    |  0         |
| 3  | Revenge   |  0         |
| 4  | Tennessee |  0         |
| 5  | Yamato    |  0         |

希望这可以帮助!

于 2019-03-17T02:31:56.930 回答
1

我知道这是一个老问题,但我希望这对任何试图找出这个练习的答案的人都有帮助

outcomes表可以包括未包含在该ships表中的船舶。

通过您的查询,您只包括ships表中的船舶,您需要包括outcomes表中的一些船舶。问题是,如何知道结果船属于哪个级别?

练习中给出了一些注释

  1. 结果关系可能包含船舶关系中不存在的船舶。

  2. 沉没的船不能参加以后的战斗。

  3. 由于历史原因,在许多演习中将领头舰称为头舰。

  4. 在 Outcomes 表中找到但不在 Ships 表中的船仍然在数据库中考虑。即使沉没也是如此。

classes该表还有另一种说法

其名称被分配到一个级别的船称为领导船。

基于此,您可以通过以下查询获取所有船舶

 SELECT name FROM ships
 UNION
 SELECT ship FROM outcomes o
 JOIN classes c ON (o.ship = c.class)

如果一艘船不在ships表中但在outcomes表中,知道它的级别的唯一方法是将船的名称与所有级别进行比较,如果匹配,则该船是主船。

这是一个可以为您提供正确答案的查询示例

WITH all_ships AS (
 SELECT name FROM ships
 UNION
 SELECT ship FROM outcomes o
 JOIN classes c ON (o.ship = c.class)
),
ships_sunked AS (
 SELECT name FROM all_ships
 JOIN outcomes o ON (o.ship = all_ships.name)
 WHERE o.result = 'sunk'
)
SELECT DISTINCT COALESCE(class, ss.name) FROM ships s
RIGHT JOIN ships_sunked ss ON (s.name = ss.name)
于 2021-05-14T18:34:15.670 回答
1

我会投票支持 Kaczmarski,因为它非常接近。有效的答案还有一行可以在第二遍时通过错误检查。

需要进行检查以确保ships.name不包含也是类名的名称。

一个有效的数据库结构将包括俾斯麦号和所有沉没在结果表和船舶表中的船只。或者,ships 表将不包含任何沉没的船只。

这种类型的方法必须在真实世界的场景中使用,在该场景中,多个用户正在修改数据库并且用户对正在修改的表具有读取权限。

select class, sum(sunks) as sunks from(
    select class, sum(case result when 'sunk' then 1 else 0 end) as sunks 
    from classes c left join outcomes o on c.class = o.ship
where class not in (select name from ships) 
    group by class
    union all
    select class, sum(case result when 'sunk' then 1 else 0 end) as sunks
    from ships s left join outcomes o on s.name = o.ship
    group by class
)as x

group by class
于 2015-11-25T17:32:04.407 回答
1

更有效的方法是:

    select class, SUM(CASE WHEN result='sunk' 
          THEN 1 
          ELSE 0 END) from
(
select class,ship as name,result from classes cc left outer join outcomes oo ON cc.class=oo.ship
union
select class,name,result from ships ss left outer join outcomes oo ON ss.name=oo.ship
) as ttt
group by class
于 2016-05-11T08:29:49.140 回答
0

There is no real difference in both queries. There can be difference if you remove group by and count from select. Because there can be more than one same ship names in different classes. Since you are using group by class then it doesn't make any difference in both queries. Both queries will return ships count per class.

于 2013-03-10T18:27:48.557 回答
0

这将是问你的 TA(助教?)的好问题。使用您书中的答案可能有“教学”原因。

尽管您的查询和书中的查询会产生相同的结果,但您的查询不能轻易修改以回答有关“类”的其他问题。例如,假设问题变为“每个国家沉没了多少艘船?”。对“图书查询”进行简单更改即可轻松实现(使用 RBarryYoung 重新格式化的代码):

SELECT classes.country, COUNT(*)
FROM classes
INNER JOIN ships    ON classes.class = ships.class
INNER JOIN outcomes ON outcomes.ship = ships.name
WHERE  outcomes.result = 'sunk'
GROUP BY classes.country;

这可能是一个微妙的点,但是以您“最感兴趣”的表作为FROM子句开始查询,然后根据需要加入其他相关表。这至少使您的代码更易于阅读。

于 2013-03-10T18:54:37.957 回答
0

您的查询没有列出每个类别,仅列出船沉没的类别,这要好一些,但似乎仍然不正确:

select class, sum(sunks) as sunks from(
    select class, sum(case result when 'sunk' then 1 else 0 end) as sunks 
    from classes c left join outcomes o on c.class = o.ship
    group by class
    union all
    select class, sum(case result when 'sunk' then 1 else 0 end) as sunks
    from ships s left join outcomes o on s.name = o.ship
    group by class
)as x
group by class
于 2015-08-24T15:23:23.153 回答