Sql query for the lowest score per country - sql

I have a database with 3 tables. In table country I have id and name columns. The sport table also has id and name columns. Finally, the table match has id, player1, and player2(that are ids of country that play one against other), winner_id (id of country that won the match) and sport_id of the sport which was played. The least wins means that I just need in which sport country had the least wins, no matther on played matches.
I want to show the sport per country with the least wins. It should look like this:
Country
Sport
Wins
France
Basketball
2
How can I construct this query? I'm using SQL Server.
Data in table look like this. Table countries:
country_id
name
1
France
2
England
Table sport:
sport_id
name
1
Footbal
2
Basketball
Table match:
match_id
player1
player2
winner_id
sport_id
1
3
1
3
1
2
6
4
4
2

I want to note that the used wording with least wins is not clear, in my solution with least wins means most matches played with least wins.
To get this ranking, we need to know how many matches a country has played in each sport and how many of those have been won.
SELECT
country.name AS country,
sport.name AS sport,
sport_wins.wins
FROM
country
OUTER APPLY (
SELECT TOP 1
t.match_count,
COALESCE(t.wins, 0) AS wins,
t.sport_id
FROM (
SELECT
COUNT(*) AS match_count,
m_c.sport_id,
t.wins
FROM match m_c
OUTER APPLY (
SELECT
COUNT(*) AS wins,
match.sport_id
FROM match
WHERE country.country_id = match.winner_id
AND match.sport_id = m_c.sport_id
GROUP BY match.sport_id
) t
WHERE country.country_id IN (m_c.player1, m_c.player2)
GROUP BY m_c.sport_id, t.wins
) t
ORDER BY t.wins ASC, t.match_count DESC
) sport_wins
JOIN sport ON sport.sport_id = sport_wins.sport_id
Please, check a demo.
If you do not take into account losses, but only the number of wins is of interest, you can use a query like this one
WITH cte AS (
SELECT
country.country_id,
sport.sport_id,
SUM(CASE WHEN match.winner_id = country.country_id THEN 1 ELSE 0 END) AS wins
FROM country
CROSS JOIN sport
JOIN match ON match.sport_id = sport.sport_id
AND country.country_id IN (match.player1, match.player2)
GROUP BY country.country_id, sport.sport_id
)
SELECT
country.name,
sport.name,
t.min_wins AS wins
FROM (
SELECT
country_id,
MIN(wins) AS min_wins
FROM cte
GROUP BY country_id
) t
JOIN cte ON cte.country_id = t.country_id AND cte.wins = min_wins
JOIN country ON cte.country_id = country.country_id
JOIN sport ON cte.sport_id = sport.sport_id
This query takes into account the fact that the country participates in matches in sport, so if a country does not compete in a sport, that sport will not be included in the statistics as it will have 0 wins and this will be the minimum value.
Please, check a demo

You need to first cross-join the sports with the countries, then get the total.
Then you can use a row-number approach to get the bottom country in each sport
SELECT
c.Country,
c.Sport,
c.Wins
FROM (
SELECT
c.name Country,
s.name Sport,
COUNT(m.winner_id) Wins,
ROW_NUMBER() OVER (PARTITION BY s.sport_id, s.name ORDER BY COUNT(m.winner_id)) rn
FROM country c
CROSS JOIN sport s
LEFT JOIN [match] m
ON s.sport_id = m.sport_id AND m.winner_id = c.country_id
GROUP BY
s.sport_id,
s.name,
c.country_id,
c.name
) c
WHERE c.rn = 1;

Related

Select the number of English players from team which scored the most goals at home on a match

TEAM
ID
TEAM_NAME
1
Arsenal
MATCH
ID
DATE
HOME_TEAM_ID
AWAY_TEAM_ID
HOME_SCORE
AWAY_SCORE
1
2018-08-10
10
7
2
1
NATION
ID
NATION_NAME
1
Spain
PLAYER
ID
NAME
NATION_ID
TEAM_ID
100
David de Gea
1
10
GOAL
GOAL_ID
MATCH_ID
PLAYER_ID
GOAL_ORDER
OWN_GOAL
1
1
106
1
False
I tried to calculate the number of English players from that team which scored the most goals at home, from the database above (SQL Server).
My query:
SELECT TOP 1 COUNT(PLAYER.PLAYER_ID), MAX(HOME_SCORE)
FROM PLAYER
JOIN NATION ON PLAYER.NATION_ID = NATION.NATION_ID
JOIN MATCH ON MATCH.HOME_TEAM_ID = PLAYER.TEAM_ID
WHERE NATION.NATION_NAME = 'England'
GROUP BY PLAYER.PLAYER_ID
ORDER BY MAX(MATCH.HOME_SCORE) DESC
It gives correct answer for the max(home_score), but the count of English players in that team isn't correct.
You need to first get the highest scoring team, then left-join NATION to PLAYER, then count the number of non-null NATION_ID.
You are also grouping by the wrong values
SELECT TOP (1)
p.TEAM_ID,
NumPlayers = COUNT(*),
NumEnglishPlayers = COUNT(n.NATION_ID),
HighestScore = m.HOME_SCORE
FROM (
SELECT TOP (1) *
FROM MATCH m
ORDER BY
m.HOME_SCORE DESC
) m
JOIN PLAYER p ON m.HOME_TEAM_ID = p.TEAM_ID
LEFT JOIN NATION n ON p.NATION_ID = n.NATION_ID
AND n.NATION_NAME = 'England'
GROUP BY
m.HOME_TEAM_ID,
m.HOME_SCORE;
db<>fiddle
Just an untested notepad scribble.
Since I can't verify it without sample data.
SELECT TOP 1
match.match_id
, match.home_score
, COUNT(CASE
WHEN player_nation.nation_name = 'England'
THEN player.player_id
END) AS EnglishPlayers
, COUNT(goal.goal_id) AS TotalGoals
FROM GOAL AS goal
JOIN PLAYER AS player
ON player.player_id = goal.player_id
JOIN MATCH AS match
ON match.match_id = goal.match_id
AND match.home_team_id = player.team_id
LEFT JOIN NATION AS player_nation
ON player_nation.nation_id = player.nation_id
GROUP BY match.match_id
ORDER BY TotalGoals DESC

The difference between the minimum and maximum number of games

Question: Show the names of all players who have the following:
the difference between the minimum and maximum number of games
this players is greater than 5.
select p.name
from player p
join competition c
on c.playerID = p.playerID
where (
(select count(*) from competition
where count(games) > 1
group by playerID
) - (
select count(*) from competition
where count(games) <= 1
group by playerID
))> 5;
I'm kind of lost. I'm not so sure is this the right way, how I should proceed: should I use count and find the minimum and maximum number of games and compare with greater than 5 or should I use instead of count, min and max functions. Would be very grateful, if someone can explain me the logic of this.
Tables:
player competition
------- --------
playerID playerID
name games
birthday date
address
telefon
SELECT
P.Name,
MIN(C.Games) MinGame,
MAX(C.Games) MaxGame,
FROM Player P
INNER JOIN Competition C
ON C.PlayerId = P.PlayerId
GROUP BY P.Id, P.Name
HAVING MAX(C.Games) - MIN(C.Games) > 5
It should be a simple query:
With tab1 AS (Select player.name, min(games) mx_game, max(games) min_game,
max(games) - min(games) diff
from player JOIN competition ON player.player_id = competition.id
group by player.player_id, player.name)
Select tab1.name from tab1
WHERE diff >5;
I am adding player_id in the group by as player_name could be similar for 2 person.

How to join tables on column containing text

I have 2 tables to merge:
t1
Continent Country City
-----------------------
Europe Germany Munich
NA Canada Ontario
Asia Singapore (blank)
Asia Japan Tokyo
AND
t2
Country Status
-----------------
Germany Complete
Canada Incomplete
Singapore Complete
Japan Complete
I want to get the continent with 2nd highest "Complete" status. I am new to SQL and I am trying hard to learn the basics, but I cannot get this done.
I understand that you want to pull out the continent that has the second most country marked as completed.
If so, you can join, aggregate, order by the count of completed countries per continent, and then filter on the second rows:
select continent
from
(select distinct country, continent from t2) t2
inner join t1 on t1.country = t2.country
group by continent
order by sum(case when status = 'Complete' then 1 else 0 end) desc
limit 1, 1
Note the use of distinct when retrieving the association of countries and continents: this is because your sample data seems like it could have more than one row per country/continent tuple (since it is referencing cities). Without the distinct, we would potientally generate duplicate rows, causing sum() to be wrong.
I understand you mean the country with more cities with status complete. You can use sub-queries:
with a as
(
select a.country,
sum(case when status = 'Complete' then 1 else 0 end) as CompleteCount
from t1 a inner join t2 b on a.country = b.country
group by a.country
)
select country from
(
select country,
ROW_NUMBER() OVER( ORDER BY CompleteCount desc) as OrderComplete
from a
)a where OrderComplete = 2

Selecting relation with exact keys in a many to many

I have an M2M relation on two tables in an SQL database, as follows:
Players
-------
Name
ID
Teams
------
Name
ID
PlayersTeams
------
PlayerID
TeamID
A team consists of 1 or more players.
I would like to query for a team given its player IDs, and return only the team that contains exactly those players, no more, no less. So querying for a team with players (1,2,3) would only return team with players 1,2,3, and not a team with players 1,2,3,4.
Is this possible in a single query?
I've got an sqlfiddle I'm trying to work it out in here: http://sqlfiddle.com/#!2/27799/8
in that example i'd like to be able to select the team "john and mick" by querying with player IDs 1 and 2...
update
in this sqlfiddle http://sqlfiddle.com/#!2/27799/69 I can select the team ID 2 ("john and mick") but it also gets team ID 4 ("john, mick and trev"). Need to filter it down to JUST 2.
select TeamId
from PlayersTeams
group by TeamId
having count(*) = sum(case when playerid in (1,2) then 1 else 0 end)
and count(*) = 2
Not familiar with mysql so I don;t know how to get the players list length (the count(*) =2) to make is fully dynamic but you get the point.
I added player 3 in team 3 to create all possible cases. This is my answer:
SELECT t.*
FROM playersteams a,
teams t
WHERE a.teamid = t.id
AND (SELECT COUNT(*) FROM playersteams c
WHERE c.teamid = a.teamid
AND c.playerid = 2) = 1
AND (SELECT COUNT(*) FROM playersteams c
WHERE c.teamid = a.teamid
AND c.playerid = 3) = 1
GROUP BY t.id, t.name
HAVING COUNT(a.playerid) = (SELECT COUNT(*) FROM players WHERE id IN (2,3));
SQL Fiddle: demo

How to write query in the following case?

I have the following table. How do I query
Table Team is as follows:
ID,Name,City,League
1,Name1,City1, A
2,Name2,City1, B
The trick is to get a COUNT(DISTINCT League) per city, and compare that number to the total number of leagues COUNT(DISTINCT League) across the whole table.
SELECT
City,
COUNT(DISTINCT League) AS numleagues
FROM yourtable
GROUP BY City
/* Only cities which have the same number of distinct leagues as the total number of distinct leagues */
HAVING COUNT(DISTINCT League) = (SELECT COUNT(DISTINCT League) FROM yourtable)
Here it is in action in SQLFiddle
All cities for which there does not exist a League which is not in the list of Leagues associated with the city:
SELECT DISTINCT City FROM Teams T1 WHERE NOT EXISTS
(SELECT * FROM Teams T2 WHERE League NOT IN
(SELECT League FROM Teams T3 WHERE T3.City = T1.City))
Almost exactly as you worded it in English, but with a twist... You want all cities that have a Name in all leagues, or to rephrase, you want all Cities where there does not exist a League that does not have a name in it from that city.;..
Select Distinct City From Table t
Where Not Exists
(Select Distinct League From Table L
Where Not Exists
(Select * From Table
Where City = t.City
And League = L.League
And Name Not in
(Select distinct Name from table
Where City = t.City) ))