SQL two table query - sql

I have 2 tables:
Players
ID
Name
1
John
2
Maya
3
Carl
Results
ID
Player_ID
Result
1
1
250
2
1
300
3
2
100
4
2
350
5
3
500
I want to select all the names from the table Players and the top scores of each person.
What I have so far:
SELECT Players.Name, max(Results.Result)
FROM Players JOIN Results
WHERE Players.ID = Results.Player_ID
But this only selects
| Carl | 500 |
and I want
| John | 300 |
| Maya | 350 |
| Carl | 500 |

try with a condition on the result : it needs to be the highest (max) for the player ID.
Try this:
SELECT p.Name, r.result FROM Players p JOIN Results r WHERE p.ID = r.Player_ID and r.result = (select max(result) from results rr where rr.Player_ID = p.ID)

You need to GROUP BY Players.ID, Players.Name to your query. I added Players.ID in case two players have the same name:
SELECT Players.Name, max(Results.Result)
FROM Players JOIN Results
WHERE Players.ID = Results.Player_ID
GROUP BY Players.ID, Players.Name

Related

Select from multiple tables where 1 record has more than 1 match in table 2

I have 2 tables, for example one with a person ID, name and food ID for an order and the second with the food ID and food name. I want to join these and return the ID, name, Food ID and Food Name but only for instances where the count of IDs and Food names are > 1 like below. Unfortunately when I try to do this I either get NULL instances from ID or it pulls the Food IDs I'm trying to exclude
Person
ID
Name
Food_ID
1
Joe
3
2
Jill
2
3
Jack
1
1
Joe
1
2
Jill
3
3
Jack
3
1
Joe
4
2
Jill
4
3
Jack
4
Food
Food ID
Food
1
Meat - Fish
2
Veg - Potato
3
Meat - Chicken
4
Veg - Broccoli
ID
Name
Food_ID
Food
1
Joe
3
Meat - Chicken
1
Joe
1
Meat - Fish
3
Jill
1
Meat - Fish
3
Jill
3
Meat - Chicken
I can do it using a temp table to get count of IDs where food like '%Meat%' and count (p.ID) > 1 but I need it to run in just a select query and I've no ID how to approach it as including a where exists just returns me NULL IDs. Apologies for how bad my SQL is but I haven't used it in years and am used to doing all my aggregation in Excel so have little idea how I'm meant to approach it, it's probably a really simple solution
SELECT p.ID, p.Name, f.Food_ID, f.Name
FROM Person p
LEFT JOIN Food f ON p.Food_ID = f.Food_ID
WHERE EXISTS (
SELECT COUNT(p.ID), COUNT(f.Food_ID)
FROM Person p
LEFT JOIN Food f ON p.Food_ID = f.Food_ID
WHERE f.Food LIKE '%Meat%'
GROUP BY p.ID
HAVING COUNT(p.id) > 1
)
GROUP BY p.ID
Try this:
SELECT
*
FROM
Person
JOIN Food ON Food.Food_ID = Person.Food_ID
WHERE
Person.ID IN (
SELECT
Person.ID
FROM
Person
JOIN Food ON Food.Food_ID = Person.Food_ID
WHERE
Food.Food LIKE '%meat%'
GROUP BY
Person.ID
HAVING
COUNT(*) > 1
)
ORDER BY
Person.ID
;
You can use a CTE to get GROUP BY p.ID HAVING COUNT(*) > 1, then get the other column values you need in your main query with a JOIN to your CTE using the p.ID column.
WITH cte AS (
SELECT
p.ID
FROM Person p
LEFT JOIN Food f ON p.Food_ID = f.Food_ID
WHERE f.Food LIKE '%Meat%'
GROUP BY p.ID
HAVING COUNT(*) > 1)
SELECT
p.ID,
p.Name,
f.Food_ID,
f.Food
FROM Person p
LEFT JOIN Food f ON p.Food_ID = f.Food_ID
INNER JOIN cte ON p.ID = cte.ID
WHERE f.Food LIKE '%Meat%'
ORDER BY p.ID ASC
Fiddle here.
Result:
ID
Name
Food_ID
Food
1
Joe
3
Meat - Chicken
1
Joe
1
Meat - Fish
3
Jack
1
Meat - Fish
3
Jack
3
Meat - Chicken
Note: Based on your provided data, I believe Jack should be listed in your result set, not Jill.

Query the sum of some cells in a table based on an id in another table

Let assume that we have two tables named family_data and person_info as below:
# family_data
person_id | family_id
1 1
2 2
3 1
4 1
5 2
# person_info
person_id | weight
1 50
2 80
3 30
4 60
5 40
How can I have a table which contains pairs of (family_id, sum_of_members_weight) as below:
# Query output:
family_id | total_weight
1 140
2 120
You can join and aggregate:
select f.family_id, sum(p.weight) total_weight
from family_data f
inner join person_info p on p.person_id = f.person_id
group by f.family_id

Condition with INNER JOIN gives wrong results

I have the following tables
goal matches team_match
id | match_id | team_id | name match_id team_id | match_id | home_away
----------------------------- ----- ------------------------------
1 1 1 Ronaldo 1 1 1 home
2 1 2 Messi 2 1 away
3 1 2 Suarez 2 1 away
Now I want to get just players who played in the away team.
SELECT DISTINCT g.name
FROM goal g
INNER JOIN matches m
ON g.match_id = m.match_id
INNER JOIN team_match tm
ON tm.match_id = m.match_id
AND tm.home_away = 'away'
WHERE m.match_id = '1'
But instead of:
Messi
Suarez
I am getting:
Ronaldo
Messi
Suarez
It seams like my second INNER JOIN is totally ignored, even if I change from "home" to "away" I will get the same result.
The INNER JOIN is working correctly. Seems your database schema is the problem.
Why shouldn't Ronaldo be in the result set? You don't use the team_id anywhere. There is no information that Ronaldo was in the team that played home in the specified match.
A suggestion for a better schema:
Table teams
team_id
1
2
Table players:
playerid team_id name
1 1 Ronaldo
2 2 Messi
3 2 Suarez
Table matches
matchid hometeamid awayteamid
1 1 2
Table goals
matchid playerid
1 1
1 2
1 3
Then your query could look like this
SELECT p.Name FROM players p
INNER JOIN goals g ON (g.playerid = p.playerid)
INNER JOIN matches m ON (m.matchid = g.matchid AND m.awayteamid = p.team_id)
WHERE m.matchid = 1
You haven't proven that the first inner join is working either.
Try removing the blank lines

SQL aggregation of columns with common value in another column

I have an unresolved doubt about a query I'm making in PostgreSQL.
I have these 2 tables
PLAYER
playerID title
1 Rondo
2 Allen
3 Pierce
4 Garnett
5 Perkins<
PLAYS
playerID TeamID
1 1
1 2
1 3
2 1
2 3
3 1
3 3
and that's my query
SELECT DISTINCT concat(N.playerID, ':', N.title), TID
FROM player N
INNER JOIN (
SELECT DISTINCT P.playerID as PID, teamID as TID
FROM plays P
) AS derivedTable
ON N.playerID = PID
ORDER BY concat
the result of the query is:
"1:Rondo" | 1
"1:Rondo" | 2
"1:Rondo" | 3
"2:Allen" | 1
"2:Allen" | 3
"3:Pierce" | 1
"3:Pierce" | 3
but I want something like that
"1:Rondo" | 1, 2, 3
"2:Allen" | 1, 3
"3:Pierce" | 1, 3
I could use an array_agg, but i really dunno how
Use string_agg()
SELECT concat(N.playerID, ':', N.title),
string_agg(p.TeamID::text, ',') as teamid_list
FROM player N
JOIN plays p ON n.playerID = p.playerID
GROUP BY n.playerID, n.title
ORDER BY 1;
Your derived table is not necessary (and the distinct even more so)
In Postgres should be:
SELECT concat(N.playerID, ':', N.title) title, string_agg(P.TID,', ') TID
FROM player N
LEFT JOIN plays P ON N.playerID = P.PID
GROUP BY 1
ORDER BY 1
For MySQL
Try this:
SELECT CONCAT(N.playerID, ':', N.title) playerTitle,
GROUP_CONCAT(P.TID SEPARATOR ', ') TID
FROM player N
LEFT JOIN plays P ON N.playerID = PID
GROUP BY N.playerID
ORDER BY playerTitle

aggregation with conditionals?

I'm trying to aggregate depending on the conditional if player_id (Gary)
has greater, equal, or less score then player_id("other")
my schema has
players(player_id, name)
matches(match_id, home_team(player_id), away_team(player_id) )
outcome(outcome_id, match_id, home_score:integer, away_score:integer
Output from:
select m.match_id, p.name AS home_team, p1.name AS away_team, o.home_score, o.away_score
from players p
inner join matches m on (p.player_id = m.home_team)
inner join players p1 on (p1.player_id = m.away_team)
inner join outcomes o on (m.match_id = o.match_id);
match_id | player_id | player_id | home_score | away_score
----------+-----------+-----------+------------+------------
1 | 1 | 2 | 1 | 2
2 | 2 | 1 | 1 | 3
3 | 3 | 1 | 3 | 2
Wanted output:
player_id | Wins | Draws | Losses
-------------+------+-------+--------
1 | 1 | 0 | 2
2 ... | ... | .. | ...
My schema are open for alteration.
EDIT(sqlfiddle): http://www.sqlfiddle.com/#!2/7b6c8/1
I would use UNION ALL to get every outcome twice, once for home and once for away player. The second time home_score/away_score should be switched, to get correct sums for away player.
select
d.player_id,
d.name,
sum(d.home_score > d.away_score) as wins,
sum(d.home_score = d.away_score) as draws,
sum(d.home_score < d.away_score) as loses
from (
select p.player_id, p.name, o.home_score, o.away_score
from players p
join matches m on p.player_id = m.home_team
join outcomes o on o.match_id = m.match_id
union all
select p.player_id, p.name, o.away_score as home_score, o.home_score as away_score
from players p
join matches m on p.player_id = m.away_team
join outcomes o on o.match_id = m.match_id) d
group by d.player_id, d.name
Returns:
PLAYER_ID NAME WINS DRAWS LOSES
1 Gary 1 0 2
2 Tom 1 0 1
3 Brad 1 0 0
sqlFiddle demo: http://www.sqlfiddle.com/#!2/7b6c8/21
For a solution without a subquery and unions: http://www.sqlfiddle.com/#!2/7b6c8/31
SELECT
p.player_id,
COALESCE(SUM(o1.home_score > o1.away_score or o2.home_score < o2.away_score), 0) wins,
COALESCE(SUM(o1.home_score = o1.away_score or o2.home_score = o2.away_score), 0) draws,
COALESCE(SUM(o1.home_score < o1.away_score or o2.home_score > o2.away_score), 0) losses
FROM players p
LEFT JOIN matches m1 ON (p.player_id = m1.home_team)
LEFT JOIN players p1 ON (p1.player_id = m1.away_team)
LEFT JOIN outcomes o1 ON (m1.match_id = o1.match_id)
LEFT JOIN matches m2 ON (p.player_id = m2.away_team)
LEFT JOIN players p2 ON (p2.player_id = m2.home_team)
LEFT JOIN outcomes o2 ON (m2.match_id = o2.match_id)
GROUP BY p.player_id
Results:
PLAYER_ID WINS DRAWS LOSSES
1 1 0 2
2 1 0 1
3 1 0 0
4 0 0 0
5 0 0 0