3

次のテーブルがあります (プレイヤー、イベント、スコア)

ここに画像の説明を入力

各プレーヤーが 2012 年に獲得したポイント数のリストが必要です。リストには、2012 年にプレーしていないプレーヤーも含め、すべてのプレーヤーを掲載したいと考えています。

したがって、理論的には次のように出力する必要があります。

Ola Hansen     6  
Tove Svendson  0  
Kari Pettersen 0

私は試した:

SELECT *, sum(Points) as Points FROM Players
LEFT OUTER JOIN Scores ON P_Id=Player
LEFT OUTER JOIN Events ON Event=E_Id AND Year='2012' 
GROUP by P_Id ORDER by Points DESC

しかし、それはすべての年のすべてのポイントを数えます。

4

4 に答える 4

3

スコアとイベントは、プレーヤーに外部結合する前に内部結合する必要があります。

サブクエリまたは括弧を使用して、この特定の結合の「優先順位」を強制することもできますが、SQL テキストで JOIN の順序を使用し、最後の JOIN をプレーヤー (この場合は RIGHT) に慎重に「方向付ける」方が適切です。

COALESCE は、NULL を 0 に変換するためだけのものです。

SELECT
    P_Id, LastName, FirstName, COALESCE(SUM(Points), 0) TotalPoints
FROM
    Scores
    JOIN Events
        ON Event = E_Id AND Year = 2012
    RIGHT JOIN Players
        ON P_Id = Player
GROUP BY
    P_Id, LastName, FirstName
ORDER BY
    TotalPoints DESC;

これにより、次が生成されます。

P_ID    LASTNAME    FIRSTNAME   TOTALPOINTS
1       Hansen      Ola         6
2       Svendson    Tove        0
3       Pettersen   Kari        0

このSQL Fiddleでそれを試すことができます。

于 2012-06-14T21:23:25.593 に答える
1

これを試して:

select firstName, lastName, sum(if(year is null, 0, points)) points from p
left join s on p_id = player
left join e on e_id = event and year = 2012
group by p_id, lastName, firstName
order by points desc

サブクエリよりもパフォーマンスが優れているはずですが、移植性は低くなります。試してみる!

これがフィドルです。

于 2012-06-14T21:03:56.827 に答える
1

人々 (私自身も含む) は「最も重要な」または「件名」のテーブルを最初に置くのが好きなので、イベントとスコアの間の結合を最初に行い、INNER JOIN として行うことで、探しているものを達成できます。

SELECT
   P.P_Id,
   P.LastName,
   P.FirstName,
   IsNull(Sum(P.Points), 0) TotalPoints
FROM
   Players P
   LEFT JOIN (
      Events E
      INNER JOIN Scores S
         ON E.Event = S.E_Id
         AND E.Year = '2012'
   ) ON P.P_Id = S.Player
GROUP BY P.P_Id, P.LastName, P.FirstName -- no silly MYSQL implicit grouping for me!
ORDER BY TotalPoints DESC

結合順序を強制する秘訣は、実際にはそれを行う ON 句の場所であるということです。括弧を削除しても機能するはずです。しかし、余分な明快さが必須だと思うので、私はそれらを使用することを好みます.

また、INNER JOIN を最初に配置し、OUTER を最後に配置することで、結合順序を強制する完全に有効な方法でもあります。ただし、最後のテーブルを最終セットのメンバーシップを決定するテーブルにする必要があります。したがって、それを RIGHT JOIN に切り替えるとうまくいきます。

SELECT
   P.P_Id,
   P.LastName,
   P.FirstName,
   IsNull(Sum(P.Points), 0) TotalPoints
FROM
   Events E
   INNER JOIN Scores S
      ON E.Event = S.E_Id
      AND E.Year = '2012'
   RIGHT JOIN Players P
      ON S.Player = P.P_Id
GROUP BY P.P_Id, P.LastName, P.FirstName
ORDER BY TotalPoints DESC

異なるテーブルで PK と FK の場合に列に異なる名前を使用することは、私の考えでは、ベスト プラクティスに対する非常に悪い違反です。すべての表で「P_Id」、またはすべての表で「Player」である必要があり、一貫性がありません。

于 2012-06-14T20:42:16.200 に答える
0
SELECT P.FIRSTNAME, P.LASTNAME,  A.Points as Points 
FROM Players P
LEFT OUTER JOIN 
(
   SELECT S.Player, sum(Points) 
   FROM Scores S, Events E 
   WHERE S.Event=E.E_Id 
   AND E.Year='2012' 
   GROUP BY S.Player
) A 
ON A.PLAYER = P.P_ID
ORDER by Points DESC

基本的に、2012年のすべてのプレーヤーとそのポイントが必要なためINNER JOIN、2012年のポイントとこのサブ結果の合計を強制するには、イベントとスコアの間に必要があります。LEFT OUTER JOIN

于 2012-06-14T20:46:27.303 に答える