How to search for multiple values on inner join - sql

I've got two tables, one with games and one with participants.
A game can have multiple participants. Now I need to search if a game is already inserted. I made a query with an inner join.
SELECT game.gameId
FROM game
INNER JOIN participants
WHERE game.gameId = participants.gameId
AND participants.name = 'Team1'
AND participants.name = 'Team2'
This isn't working the way I expected, is there a way to check if there is a match between teams 1 and 2 in one query?
Thanks!
edit
tablelayout:
**game**
PK gameId
date
**participants**
PK id
FK gameId
name
type //home or visiting

The following should work. It will JOIN games and participants using the gameID and ensure that the names are Team1 and Team2. This assumes that participants is a many to many with games and that there are only two teams per game.
SELECT participants.gameId
FROM game
JOIN participants
ON game.gameId = participants.gameId
WHERE participants.name = 'Team1'
OR participants.name = 'Team2'
GROUP BY participants.gameID
HAVING COUNT(*) = 2

You're not trying to relate game to participants, but participants to itself.
select
p1.gameId
from
participants as p1, participants as p2
where
p1.name = 'Team1' and p2.name='Team2' and p1.gameId = p2.gameId

you need to join twice with the participants table:
SELECT game.gameId
FROM game
INNER JOIN participants p1
ON game.gameId = p1.gameID
INNER JOIN participants p2
ON game.gameId = p2.gameID
WHERE (p1.name = 'Team1' AND p2.name = 'Team2')
OR (p2.name = 'Team1' AND p1.name = 'Team2')

Related

How to count the difference between two values in SQL?

Sorry if my title is not detailed
I have two tables
Game table:
homeTeam int
awayTeam int
homePoints int
awayPoints int
Team
tid int
name varchar(20)
I am trying to find the number of games won at home by a specific team, lets say 'cops', with Team.tid = Game.homeTeam and wins are counted if homePoints > awayPoints
I want to end up with
Team HomeWins
-----------------
Cops 20
How do I go about that?
EDIT: #
I Managed to get my answer using
SELECT t.name, count(CASE WHEN homePoints > awayPoints then 1 ELSE NULL END) as "Home Wins"
from Team t
JOIN Game g
ON t.tid = g.homeTeam
where t.name = 'Patriots'
GROUP BY t.name
some of the other answers were giving me the following errors
Column 'team.name' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
You should join the tables to be able to get both name and homePoints and use COUNT by homePoints and group by using team id to see a result for each team.
SELECT
T.name, COUNT(G.homePoints)
FROM
team T
INNER JOIN
game G ON G.homeTeam = T.tid
WHERE
G.homePoints > G.awayPoints
GROUP BY T.tid, T.name;
OR if you need the result for a specific team by providing it's id, you may drop the GROUP BY and add condition in the WHERE, e.g.
SELECT
T.name, COUNT(T.tid)
FROM
team T
INNER JOIN
game G ON G.homeTeam = T.tid
WHERE
G.homePoints > G.awayPoints and T.tid = :request_team_id;
First SELECT the columns that we want to display and use AS to specify they headings.
SELECT
team.name as 'Team',
COUNT(game.homePoints) AS 'HomeWins'
FROM dbo.team
Then we use INNER JOIN to only include the entries in game table, which match the Team ID in the homeTeam column vs what we selected from the team table.
INNER JOIN game on team.tid = game.homeTeam
Then we add a WHERE clause to limit it to only the team we ask for team.name = 'cops' and only include wins by that team
WHERE
team.name = 'cops'
AND game.homePoints > game.awayPoints
So all together your script should look like this;
SELECT
team.name as 'Team',
COUNT(game.homePoints) AS 'HomeWins'
FROM dbo.team
INNER JOIN game on team.tid = game.homeTeam
WHERE
team.name = 'cops'
AND game.homePoints > game.awayPoints
GROUP BY team.name

Select a list of all game titles bought by those who have purchased a specified game

I want to select the list of games purchased by players who bought 'this_game'
Here is my base of 3 tables :
PLAYERS(IDP INT PK, PSEUDO VARCHAR)
GAMES(IDG INT PK, TITLE VARCHAR)
SALES(IDP INT FK, IDG INT FK)
I've tried something like that but it's not correct:
SELECT TITLE from SALES
JOIN GAMES on SALES.IDG = GAMES.IDG
JOIN PLAYERS on SALES.IDP = PLAYERS.IDP
GROUP BY TITLE
HAVING TITLE= 'this_game'
I've tried different things but none of them worked.
With a join on all 3 tables:
select distinct g.title
from games g
inner join sales s on s.idg = g.idg
inner join players p on p.idp = s.idp
where p.idp in (
select s.idp
from sales s inner join games g
on g.idg = s.idg
where g.title = 'this_game'
)
You do not need the players table to solve this -- nor a subquery, although that is not a problem:
select distinct g2.title
from games g1 join
sales s1
on g1.idg = s1.idg and
g1.title = 'this game' join
sales s2
on s1.idp = s2.idp join -- same person
games g2
on g2.idg = s2.idg;

three tables relations SQL select

I'm learning SQL, so help is greatly appreciated.
I have three tables: league, player and team
league and player is many to many (as a player can be in more than one league)
team and player is many to many (as a player can be on a team in multiple leagues)
league and team is one to many.
I have the following table ids:
league.id ----. league_has_player (league_id, player_id) .------ player.id
team.id ----. team_has_player (team_id, player_id) .----- player.id
league ----. team.id (team.league_id)
I want to get all the players in the league who are not on a team in the league.
Here's my broken attempt.
Select *
from player p,
join team t on t.league_id = l.id
join league l on league.id = 2
where p.id = league_has_player.player_id and
not in (select team_has_player.player_id from team_has_player)
I think you're trying more for something like this. As a couple comments have pointed out, your table schema isn't clear. But this is the impression I get from your attempt.
DECALRE #leagueId...
SELECT *
FROM player
WHERE player.id IN (SELECT player_id
FROM league_has_player
WHERE league_id = #leagueId) AND
player.id NOT IN (SELECT player_id
FROM team_has_player
INNER JOIN team ON team.Id = team_has_player.team_id
WHERE team.league_id = #leagueId)
Get all the players registered for the league, where they don't belong to a team in the league.
SELECT p.*, lp.league_id
FROM player p
JOIN league_has_player lp ON lp.player_id = p.id
WHERE NOT EXISTS (select 1
FROM team_has_player tp
JOIN team t ON t.id = tp.team_id
AND tp.player_id = p.player_id
AND t.league_id = lp.league_id)

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

Complicated SQL Query involving multiple tables

In this Query, I have to list pair of players with their playerID and playerName who play for the exact same teams.If a player plays for 3 teams, the other has to play for exact same 3 teams. No less, no more. If two players currently do not play for any team, they should also be included. The query should return (playerID1, playername1, playerID2, playerName2) with no repetition such as if player 1 info comes before player 2, there should not be another tuple with player 2 info coming before player 1.
For example if player A plays for yankees and redsox, and player b plays for Yankees, Red Sox, and Dodgers I should not get them. They both have to play for Yankees, and Red Sox and no one else. Right now this query finds answer if players play for any same team.
player(playerID: integer, playerName: string)
team(teamID: integer, teamName: string, sport: string)
plays(playerID: integer, teamID: integer)
Right now the Query I have is
SELECT p1.playerID, p1.playerName, p2.playerID, p2.playerName
FROM player p1, player p2, plays
WHERE p1.teamID = p2.teamID AND teamID in.....
I am stuck on how to approach it after this. Any hints on how to approach this problem. Thanks for your time.
I think the easiest approach is to concatenate the teams together and just join on the results. Postgres provides the function string_agg() to aggregate strings:
select p1.playerId, p1.playerName, p2.playerId, p2.playerName
from (select p.playerId, string_agg(cast(p.TeamId as varchar(255)), ',' order by TeamId) as teams,
pp.PlayerName
from plays p join
players pp
on p.playerId = pp.playerId
group by p.playerId
) p1 join
(select p.playerId, string_agg(cast(p.TeamId as varchar(255)), ',' order by TeamId) as teams,
pp.PlayerName
from plays p join
players pp
on p.playerId = pp.playerId
group by p.playerId
) p2
on p1.playerid < p2.playerid and p1.teams = p2.teams;
EDIT:
You can do this without string_agg. The idea is to start with a list of all possible player combinations.
Then, join in the teams for the first player using left outer join. And join in the teams for the second by using full outer join and matching on the team and driver name. The reason you need the driver table is to be sure that the id/name does not get lost in the full outer join:
select driver.playerid1, driver.playerid2
from (select p1.playerId as playerId1, p1.playerName as playerName1,
p2.playerId as playerId2, p1.playerName as playerName2
from players p1 cross join
players p2
where p1.playerId < p2.playerId
) driver left outer join
plays p1
on p1.playerId = driver.playerId full outer join
plays p2
on p2.playerId = driver.playerId and
p2.teamid = p1.teamid
group by driver.playerid1, driver.playerid2
having count(p1.playerid) = count(*) and
count(p2.playerid) = count(*);
This joins two players on the team id (with ordering so a pair only gets considered once). It then says there is a match when all the rows for the two players have non-NULL team values. This is perhaps more clear with the equivalent having clause:
having sum(case when p1.playerid is null then 1 else 0 end) = 0 and
sum(case when p2.playerid is null then 1 else 0 end) = 0;
The full outer join will produce NULL values when two players have teams that don't match. So, no NULL values mean that all the teams match.
This is an adaptation of my answer to a previous question of yours.
Get all unique combinations of players using a triangular join:
SELECT p1.playerID, p1.playerName, p2.playerID, p2.playerName
FROM player p1
INNER JOIN player p2 ON p1.playerID < p2.playerID
Subtract the second player's team set from that of the first player and check if there are no rows in the result:
NOT EXISTS (
SELECT teamID
FROM plays
WHERE playerID = p1.playerID
EXCEPT
SELECT teamID
FROM plays
WHERE playerID = p2.playerID
)
Swap the sets, subtract and check again:
NOT EXISTS (
SELECT teamID
FROM plays
WHERE playerID = p2.playerID
EXCEPT
SELECT teamID
FROM plays
WHERE playerID = p1.playerID
)
Finally, apply both conditions to the result of the triangular join in Step 1.
SELECT p1.playerID, p1.playerName, p2.playerID, p2.playerName
FROM player p1
INNER JOIN player p2 ON p1.playerID < p2.playerID
WHERE
NOT EXISTS (
SELECT teamID
FROM plays
WHERE playerID = p1.playerID
EXCEPT
SELECT teamID
FROM plays
WHERE playerID = p2.playerID
)
AND
NOT EXISTS (
SELECT teamID
FROM plays
WHERE playerID = p2.playerID
EXCEPT
SELECT teamID
FROM plays
WHERE playerID = p1.playerID
)
;