SQL MS Access join help average not correct - sql

I am trying to create a query that displays the average attendance by conference when at least one team was in a game.
Relationships
this is very close to what im looking for
SELECT
Conference.ConferenceName,
AVG(Game.Attendance) AS AVG_ATT
FROM
(
Conference
INNER JOIN School ON Conference.[ConferenceID] = School.[ConferenceID]
)
INNER JOIN Game ON
(
School.[SchoolID] = Game.[Team1]
OR
School.[SchoolID] = Game.[Team2]
)
GROUP BY
Conference.ConferenceName;
the problem is if a game has 2 teams from the same conference it adds the attendance twice, and should only do it once.
consider 2 games
game1
Team1- Wisconsin
Conference - BIG10
Team2 - Michigan
Conference - BIG10
Attendance - 100,000
game2
Team1- Wisconsin
Conference - BIG10
Team2 - USC
Conference - PAC12
Attendance - 65,000
Results
BIG10-correct 82,500
PAC12 65,000
BIG10-Actual 88,333

Get a distinct list of the games by conference in a derived query, then do your average.
SELECT
ConferenceName,
AVG(Attendance) AS AVG_ATT
FROM
(
SELECT DISTINCT
GameID,
Conference.ConferenceName,
Game.Attendance
FROM
(
Conference
INNER JOIN School ON Conference.[ConferenceID] = School.[ConferenceID]
)
INNER JOIN Game ON
(
School.[SchoolID] = Game.[Team1]
OR
School.[SchoolID] = Game.[Team2]
)
) DerivedDistinctGamesAndConferences
GROUP BY
ConferenceName;

USE UNION to discard duplicated first before doing the average
SELECT
Game.GameID
Game.Attendance
Conference.ConferenceName
FROM
(
Conference
INNER JOIN School ON Conference.[ConferenceID] = School.[ConferenceID]
)
INNER JOIN Game ON
(
School.[SchoolID] = Game.[Team1] -- TEAM 1
)
UNION
SELECT
Game.GameID
Game.Attendance
Conference.ConferenceName
FROM
(
Conference
INNER JOIN School ON Conference.[ConferenceID] = School.[ConferenceID]
)
INNER JOIN Game ON
(
School.[SchoolID] = Game.[Team2] -- TEAM 2
)
So you will get query1 union query2
GameID Attendance Conference
1 100,000 BIG10 < one row will disapear
2 80,000 BIG10
1 100,000 BIG10 < after union
2 80,000 PAC12
Then you calculate the avergage over this result

I am not exactly sure in terms of coding, but conceptually, the fact that you need to aggregate totals "when at least one" team was- as you then say, only ONCE- at a conference, makes me intuit you may need to use some "if...then" clause statements within VBA script to get the specific calculation you want. Right now, the SQL "or" statement isn't enough.

Related

2 Left joins put together multiplying the results. But it shouldn't

I am building a chat site and for presenting the chats to the audiences, I have 3 Dropdownlists - Sports (Default is All Sports), Day/Month/Year, Users online/Total Users.
Now, if by default all sports is selected and I pick 1 month and Total users, the expected result should be
My query is
SELECT DISTINCT roo.[Sports],
roo.[Name],
COUNT(DISTINCT chu.ChatUserLogId) AS TotalUsers,
COUNT(DISTINCT liu.[LoggedInUserID]) AS UserOnline
FROM Room AS roo
LEFT JOIN LoggedInUser AS liu ON roo.RoomID = liu.RoomID
LEFT JOIN ChatUserLog AS chu ON roo.RoomID = chu.RoomID
AND chu.LoggedInTime >= DATEADD(DAY,-30,GETDATE())
GROUP BY roo.[Sports], roo.[Name]
ORDER BY TotalUsers DESC
One person suggested that with my method I am actually multiplying the row because of the two joins & so I need to aggregate first, then join.
So in the end, I tried this query too
with agg_ChatUserLog as (select RoomId, count(*) as cnt_user_tot from ChatUserLog WHERE LoggedInTime >= DATEADD(DAY,-30,GETDATE()) group by RoomId),
agg_LoggedInUser as (select RoomId, count(*) as cnt_user_logged from LoggedInUser group by RoomId)
select Sports, Name, cnt_user_tot, cnt_user_logged from Room r
left outer join agg_ChatUserLog acu on acu.RoomId = r.RoomId
left outer join agg_LoggedInUser alu on alu.RoomId = r.RoomId;
But this is also multiplying the results.
Where am I making the mistake in both the query? Thanks in advance and have a nice day ahead.
SAMPLE DATA IS:
Chatroom name Total Users Online users
Basketball
Roomname27 32 5
Roomname11 15 3
Roomname32 8 1
Football
Roomname5 63 12
Roomname18 44 7
Roomname4 15 2
you can try another syntax :
select Sports,
Name,
coalesce(
(
select count(distinct C.ChatUserLogId)
from ChatUserLog as C
where C.RoomId = R.RoomId
and C.LoggedInTime >= DATEADD(DAY,-30,GETDATE())
),
0) AS TotalUsers,
coalesce(
(
select count(distinct D.LoggedInUserID)
from LoggedInUser as D
where D.RoomId = R.RoomId
),
0) AS UserOnline
from Room R
with this syntax, you will never have more results than number of roomname.
but you also have room whitout audience

How do I join to one row if there are several join matches?

I have 2 tables. I want to join in a way that the latest date is joined for that player. From the below subset, I want the join for Adams to only join to the row with the draw because it was the latest date-wise. How do I go about doing this when you have multiple rows?
ID PLAYER
-------------
2 Adams
3 Rogers
4 David
PLAYER_ID DATE RESULT
------------------------------------
2 01/01/2014 Win
2 01/02/2014 Win
2 01/03/2014 Loss
2 01/04/2014 Draw
I'm assuming player_id and date is a unique combination. Date isn't a good column name. I've assumed your tables names are player and result...in the future, give us table names so answers can include them instead of my guesses.
Building the query:
(select player_ID, max(date) from table group by player_ID)
That will select the maximum date for each player. We are going to use it as a subquery and inner join to it so it acts as a filter. Note that if the player_ID, date combination isn't unique, this will bring back multiple rows per player.
Select player, maxdate
from player p
inner join (select player_ID, max(date) as maxdate from result group by player_ID) a
on a.player_ID = p.player_ID
This will return to you a player and the most recent date. Join that back to the result table to get the result
Select player, result
from player p
inner join (select player_ID, max(date) as maxdate from result group by player_ID) a
on a.player_ID = p.player_ID
inner join result r on r.player_ID = a.player_ID and r.date = a.maxdate
Hopefully that makes sense as to the logic in creating the statement for you.

SQL Group By Before Averaging

Currently I have a query that finds the average of points scored depending upon opponent.
Here is the query:
SELECT NBAGameLog.Opp, AVG(NBAGameLog.Points)
FROM Players INNER JOIN
NBAGameLog
ON Players.Player_ID = NBAGameLog.Player_ID
WHERE (NBAGameLog.Date_Played Between Date()-15 And Date() AND
Players.Position = "C"
GROUP BY NBAGameLog.Opp;
The issue happens if I have something like this:
NBAGameLog table:
Player_ID Team Opp Points Position
1 MIA ATL 15 C
2 MIA ATL 25 C
3 BOS ATL 23 C
The result from this would be:
Position Opp Average
C ATL 21
But I'd like the query to first group together the Teams. So instead of (15+25+23)/3, it would see that the first two players were on the same team, so only count that as one and do (40+23)/2
Is this possible?
You can do this using a subquery, aggregating first in the subquery then again in the outer query:
SELECT t.Opp, avg(Points)
FROM (SELECT gl.team, gl.Opp, AVG(gl.Points) as Points
FROM Players p INNER JOIN
NBAGameLog gl
ON p.Player_ID = gl.Player_ID
WHERE (gl.Date_Played Between Date()-15 And Date() AND
p.Position = "C"
GROUP BY gl.team, gl.Opp;
) t
GROUP BY t.Opp;

New to SQL, having trouble with table with two IDs

I have a DB of scores over the course of a season and I am having trouble with a query to return the season results for a given team. Here is a snapshot of the table involved:
Teams (tid, team_name)
Games (home_team_id, road_team_id, game_date, home_score, road_score)
What would the SQL look like to return all games where home_team_id or road_team_id is 1 and include the team_name of the opponent?
Not clearly stated in question, but I guess your main confusion is on how to get team_name from both home_team_id and road_team_id. You can do twice INNER JOIN for that purpose, for example :
select
g.*
, home.team_name as home_team_name
, road.team_name as road_team_name
from Games g
inner join Teams home on home.tid = g.home_team_id
inner join Teams road on road.tid = g.road_team_id
where g.home_team_id = 1
or g.road_team_id = 1

Trouble With GROUP BY Learning Derby SQL

I have formed this query to produce the pitcher from each team who has the most wins. My trouble comes in that I need to group them a certain way and I keep having scoping issues when trying to do so. W is the number of wins for each pitcher. Here is my pre-grouped statement...
SELECT
(SELECT p1.nameFirst FROM Players p1 Where (one.playerID = p1.playerID)),
(SELECT p1.nameLast FROM Players p1 Where (one.playerID = p1.playerID)),
one.W, (SELECT t1.name FROM Teams t1 Where(one.teamID = t1.teamID))
FROM Pitching one
Where (one.W >= ALL
(SELECT two.W
FROM Pitching two
Where (two.teamID = one.teamID)));
I need to group the tuples by league and within the leagues group by division. League (lgID) and division (divID) exist in the Teams table. Can someone point me in the right direction? Thank you.
This is top six rows of what is currently output...
Zach Britton 11 Baltimore Orioles
Mark Buehrle 13 Chicago White Sox
Madison Bumgarner 13 San Francisco Giants
Jhoulys Chacin 11 Colorado Rockies
Bruce Chen 12 Kansas City Royals
Kevin Correia 12 Pittsburgh Pirates
My desired output is to have these teams sorted by league (NL/AL) and within the leagues have them sorted by division.
Based on your updated comment. I think this is what you want.
SELECT
pl.nameFirst
, pl.nameLast
, p.W
, t.name
FROM
(
SELECT
MAX(p1.W) AS W
, p1.teamId
FROM
Pitching p1
GROUP BY
p1.teamId
) t1
JOIN
Pitching p
ON t1.W = p.W
AND t1.teamId = p.teamId
JOIN
Players pl
ON p.playerID = pl.playerID
JOIN
Teams t
ON p.teamID = t.teamID
ORDER BY
t.lgID
, t.divID
I do agree with swasheck, there are some opportunities for improvement in your schema. As swascheck said, teamId should be in Players. Not in Pitching.
This may be an issue of structure. Using what I believe to be your structure we could probably narrow it down like this:
select Players.nameFirst, Players.nameLast, TopPitcher.Winner,
Teams.name, League.Name, Division.Name
from (select playerID, max(Wins) as Winner
from (select playerID, teamID, count(W) as Wins
from Pitching
group by playerID, teamID ) PitchingWins) TopPitcher
join Players
on TopPitcher.playerID = Players.playerID
join Teams
on Teams.teamID = Players.teamID
join League
on Teams.leagueID = League.leagueID
join Division
on League.divisionID = Division.divisionID
order by League.Name, Division.Name
Now. Having said that, this is only for the structure you've given (with some other interpolation). Your overall structure is faulty as I would probably relate Player to Teams and not Pitching to Teams since you might get some sort of data errors regarding team wins vs. pitcher wins.