2013-03-10 55 views
1

表:SQL查詢示例(是我的答案是否正確?)

  • 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表,是不是我的查詢蘇fficient?我在做同樣的事情,但沒有加入classes表。提前致謝。

+4

這是什麼「樣書」你正在閱讀的是具有SQL查詢與語法20年過時了嗎? – RBarryYoung 2013-03-10 18:18:12

+0

您的查詢是正確的,但可以通過加入您的表格進行改進 – 2013-03-10 18:23:10

+0

@RBarryYoung Dunno我在線提供了示例問題。這些是TA的一些幻燈片。沒有提到日期。 – user1071840 2013-03-10 18:26:42

回答

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; 
+0

意思是,(舊式)equi-join語法('WHERE tableA.fk = tableB.pk')總是執行一個'OUTER JOIN'? – stakx 2013-03-10 18:21:19

+0

@stakx否,如果使用'=',則舊語法將執行內連接,如果使用'= *'或'* =',則會使用外連接。 – RBarryYoung 2013-03-10 18:24:46

+0

@stakx哎呀,我明白你的意思了。沒有我最初的答案是不正確的。我會糾正...... – RBarryYoung 2013-03-10 18:25:38

0

這兩個查詢沒有真正的區別。如果您從組中刪除組並從中進行計數,則可能會有所不同。因爲在不同的班級中可以有多個相同的船名。由於您按類使用組,所以在兩個查詢中都沒有任何區別。這兩個查詢將返回每班船隻數量。

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子句,然後根據需要加入其他相關表。這至少可以讓你的代碼更易於閱讀。

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 
1

我會投了卡奇馬爾斯基,因爲它是非常接近的。有效的答案在第二遍時有一個額外的路線來通過錯誤檢查。

需要檢查以確保ships.name不包含名稱,該名稱也是類名稱。

一個高效的數據庫結構將包括俾斯麥號和沉沒在結果表和船舶表中的所有船隻。或者船隻表中不會包含沉沒的船隻。

這種類型的方法必須用於現實世界中,其中數據庫正在被多個用戶修改,並且用戶可以讀取正在修改的表的訪問權限。

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 
+0

歡迎來到Stack Overflow。你的答案很難做好準備。考慮編輯它並適當地格式化它。 – 2015-11-25 17:34:53

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 
0

最簡單的答案...

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