I have the following tables (Players, Events, Scores)
I would like a list of how many points each player has got in 2012. I want the list to feature all of the players, even though some haven't played in 2012.
So in theory it should print:
Ola Hansen 6
Tove Svendson 0
Kari Pettersen 0
I tried:
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
But that counts all the points from all the years.
Scores and events need to be inner-joined before outer-joining them to players.
We could use a subquery or parentheses to force this particular join "precedence", but it's nicer to just use the order of JOINs in the SQL text, and then carefully "orient" the last JOIN to players (RIGHT in this case).
The COALESCE is just for converting NULLs to 0s.
This produces:
You can play with it in this SQL Fiddle.
Try this:
I guess it should perform better than a subquery... but will be less portable. Give it a try!
Here is the fiddle.
Since people (myself included) like to put the "most important" or "subject" table first, you can accomplish what you're looking for by making the join between Events and Scores occur first and as an INNER JOIN:
The trick about enforcing join order is that really it's the location of the ON clause that does it—you can remove the parentheses and it should still work. But I prefer to use them because I think the extra clarity is a must.
It's also a perfectly valid way to enforce join order by putting your INNER JOINs first and the OUTER last. Only, you want the last table to be the one that dictates membership in the final set. So switching it to RIGHT JOIN will do the trick:
I feel compelled to add that using different names for a column when it is PK vs. FK in different tables is in my mind a really bad violation of best practice. It should be "P_Id" in all tables, or "Player" in all tables, and not be inconsistent.
basically you need an
INNER JOIN
between events and Scores to force the sum of the points of the 2012 and aLEFT OUTER JOIN
with this subresult, because you want all the players + their points in the 2012.