Get combined data about two players from a table with game matches - mysql

I have a table with matches, each row containing two foreign keys, each one referencing a player from a separate table with players.
How can I select data so that it returns complete data of both players in a single row, like their name and surname?
SELECT * FROM Matches
JOIN Players ON Matches.Player1_ID=Players.Player_ID
JOIN Players ON Matches.Player2_ID=Players.Player_ID
This doesn't work

You can set aliases of table using as, and then join.
SELECT Matches.*, Ps1.*, Ps2.* FROM Matches
JOIN Players as Ps1 ON Matches.Player1_ID=Ps1.Player_ID
JOIN Players as Ps2 ON Matches.Player2_ID=Ps2.Player_ID

Related

SQL count() not showing values of 0

i just started my journey with SQL, and made some tables of Cyclists, and Cycling Teams.
Cyclist's table contains columns: ID, Name, Team (which is foreign key of TEAMS ID)
Team's table contains columns: ID, Name, Number of Cyclists
I want to Count number of Cyclists in each team, by using count() function ( Or basically any function, i just want to make it work )
After many minutes i figured out this query:
SELECT teams.name,
count(*) AS NumberOfCyclists FROM cyclists
JOIN teams ON cyclists.team = teams.id
group by teams.name;
and i Achieved this:
Which is all good, but when i LEFT JOIN i achieve:
My question is: How to get all of the teams (there are 15 of them, not 11), even those where the count of the cyclists is 0?
I think you misunderstand how LEFT JOIN works. The order of tables in the join is important. In a LEFT JOIN, the query returns all the rows in the left table, even if there are no matching rows in the right table. In your query, the left table is cyclists, and the right table is teams.
So your query is currently returning all cyclists, including those who have no team (the result shows that there are 3 cyclists who have no team). This is the reverse of what you want, which is all teams, even those with no cyclists.
If you want to return all the teams, then either reverse the tables in your join:
...
FROM teams
LEFT OUTER JOIN cyclists ON cyclists.team = teams.id
...
Or you could achieve the same result by using RIGHT join.
...
FROM cyclists
RIGHT OUTER JOIN teams ON cyclists.team = teams.id
...
You must count not the amount of rows (COUNT(*)) which cannot be zero but the amount of non-NULL values in definite column (the column which is used in joining condition usage is recommended) taken from right table (COUNT(table.column)). With LEFT JOIN, of course.
But the logic needs teams table to be left. And finally:
SELECT teams.name,
count(cyclists.team) AS NumberOfCyclists
FROM teams
LEFT JOIN cyclists ON cyclists.team = teams.id
group by teams.name;
Try this:
SELECT teams.name,
count(cyclists.id) AS NumberOfCyclists
FROM teams
LEFT JOIN cyclists ON cyclists.team = teams.id
group by teams.name;
The reason why this works instead of the way you have it is because it selects Teams as the base table to draw results from instead of Cyclists.
If there isn't a Cyclist record corresponding to a Team, then the Team is essentially null, and they are grouped together as such (with a null name). By going from Teams into Cyclists, you are saying to take each Team and find the Cyclist records corresponding to the Team, in which case there could be 0 or more.
As you LEFT JOIN, you get all rows from the table cyclists which can have a partner teams, when not all teams rows are NULL
So you have rows that have no oartner

how to join one column to all columns from another table

I have two tables, players and lineup table with all players in the team
the lineup table have this columns
`match_id`, `goalkeeper`, `center_back`, `center_back_2`, `right_outside_back`, `left_outside_back`, `defensive_center_midfielder`, `center_midfielder`, `attacking_center_midfielder`, `right_winger`, `left_winger`, `center_forward`
and all of the columns have the ID of the one player in the players table
How to join all the columns here to the player table ?
something in line with this:
select match_id,
gk.player_name as goalkeeper,
c_back.player_name as center_back
from matches
left join players as gk on gk.id = matches.goalkeeper
left join players as c_back on c_back.id = matches.center_back
...
where match_id = x
basically a lot of left_joins.
If you redesing your database model and add table that will have columns:
match_id, position_id, player_id things will be much simpler and database engine will be grateful to you.
then your SQL would look much simpler:
select positions.* from position_definition as positions
left join (select mp.*, players.player_name from match_players as mp left join players on mp.player_id = players.id where match_id = x)
as team on team.position_id = positions.id
(something like that, did not check for accuracy here) there is additional table added holding a list of all positions in a match.

Duplicate on MYSQL results when using inner join

I am trying to list two attributes(booking.roomno and room.price) with the condition that "booking.DATETO is not null" from two different tables.
Table: Booking! Table:Room!
I have tried using this command
select booking.roomno,room.price
from booking
inner join room on booking.ROOMNO=room.roomno
where booking.dateto is not null
although the return results came in with duplicated roomno and price like shown below
room.roomno is not unique. It is only unique within a given hotel and your room table contains multiple hotels. You are going to have to specify hotelno in your join condition as well. Also since you might have multiple bookings for the same room (i.e., duplicates in booking table) you will need to do a DISTINCT to prevent that (but then you have to include the hotelno column in your field list):
select DISTINCT booking.roomno,room.price, room.hotelno
from booking
inner join room on booking.ROOMNO=room.roomno
AND booking.hotelno=room.hotelno
where booking.dateto is not null
You have two bookings for the same room so the returned rows match your inner join. You seem to be trying to fetch all the rooms that have bookings. You would achieve that by adding DISTINCTROW before the selected fields.
select DISTINCTROW booking.hotelno, booking.roomno,room.price
from booking
inner join room on booking.ROOMNO=room.roomno AND
booking.HOTELNO=room.HOTELNO
where booking.dateto is not null

SQL Select Statement Duplicates

I have three SQL Tables (Movies, MovieCopy and RentalTransactions). Movies holds data about Movies, MovieCopy holds data in relation to the number of copies of a particular DVD etc and is used as an associative entity between Movies and RentalTransactions, RentalTransactions holds data about Movie Rentals.
Movies has 10 rows of data (Movie1, Movie2, Movie 3 etc up to 10). MovieCopy has 30 rows, these 30 rows are made up of 3 copies of each of the 10 films in the Movies table. RentalTransactions has 10 rows, which relate to the first 10 rows in MovieCopy.
I am trying to run a report which will show me all the movies of type 'DVD' which are currently not out on loan, so this would be the 20 remaining copies of films in the MovieCopy table.
Below is my SQL code for trying to pull this report but when I execute this SQL i am returned 290 rows, I'm not sure why this is exactly happening, ideally I would like to see only the 20 rows in MovieCopy which are not in RentalTransactions.
Select Movies.Movie_Name, Movies.Movie_Type,
Movies.Movie_Medium, Count(MovieCopy.Movie_CopyID) as Copies
FROM Movies,MovieCopy,RentalTransactions
WHERE Movies.Movie_Medium = 'DVD' and Movies.MovieID = MovieCopy.MovieID
and MovieCopy.Movie_CopyID <> RentalTransactions.Movie_CopyID;
Can anyone see my mistake?
Select Movies.Movie_Name, Movies.Movie_Type,
Movies.Movie_Medium, Count(MovieCopy.Movie_CopyID) as Copies
FROM Movies,MovieCopy,RentalTransactions
WHERE Movies.Movie_Medium = 'DVD' and Movies.MovieID = MovieCopy.MovieID
and MovieCopy.Movie_CopyID NOT IN (SELECT Movie_CopyID FROM RentalTransactions );
Use NOT EXISTS to remove all rows from MovieCopy where a RentalTransactions exist, and GROUP BY to get the counters per movie.
Select
Movies.Movie_Name, Movies.Movie_Type, Movies.Movie_Medium,
Count(1) as Copies
FROM Movies
JOIN MovieCopy ON ( MovieCopy.MovieId = Movies.MovieId )
WHERE Movies.Movie_Medium = 'DVD'
NOT EXISTS
(
SELECT 1
FROM RentalTransactions
WHERE RentalTransactions.Movie_CopyID = MovieCopy.Movie_CopyID
)
GROUP BY
Movies.Movie_Name, Movies.Movie_Type, Movies.Movie_Medium
Your table structure is wrong. You are using the presence of an entry in RentalTransactions as a flag for the copy being rented or not. However, when you do your query this does not work as you expect. The query will find all cases where a movie is of type 'DVD' and has a corresponding entry in MovieCopy but for each transaction that is not itself. This will create duplicates.
Also, this will force you to delete entries every time someone returns the movie copy which will destroy any form of history.
What you need to have is create a new attribute in MovieCopy and set it to true/false depending on if the copy was rented or not.
This is a somewhat complicated query. Your version seems to have three flaws. The first is inconsistent use of table names, such as Transactions in the from clause and RentalTransactions as an alias. The second is the use of old-style joins. The third is inconsistent use of the group by.
Because one way to formulate the query is using a left outer join, the old-style implicit joins are a real problem.
The logic is to filter the movies based on the medium. Then, left outer join to the rental table and choose only copies with no rental record.
Select m.Movie_Name, m.Movie_Type,
m.Movie_Medium, Count(MovieCopy.Movie_CopyID) as Copies
FROM Movies m join
MovieCopyRental mcr
on m.MovieID = mc.MovieID and m.Movie_Medium = 'DVD' left outer join
RentalTransactions rt
on mcr.Movie_CopyID = rt.Movie_CopyID and
WHERE rt.Movie_CopyId is NULL
GROUP BY m.Movie_Name, m.Movie_Type, m.Movie_Medium;
If you want a list of all movies, including those with no copies, then change the where clause to conditional aggregation:
Select m.Movie_Name, m.Movie_Type, m.Movie_Medium,
count(*) as TotalCopies, sum(rt.Movie_CopyId is NULL) as RemainingCopies
FROM Movies m join
MovieCopyRental mcr
on m.MovieID = mc.MovieID and m.Movie_Medium = 'DVD' left outer join
RentalTransactions rt
on mcr.Movie_CopyID = rt.Movie_CopyID and
GROUP BY m.Movie_Name, m.Movie_Type, m.Movie_Medium;
you could do this
select mov.movie_id , mov.movietitle , cpm.movie_id , cpm.movietitle from tbl_movies as mov
left join tbl_moviescopy as cpm on cpm.movie_id = mov.movie_id
where movie_type = 'DVD'
and movie_id not exists (select movie_id from rentaltransactions)
im sorry , created my own field names based on your question.
but hope it helps you, this would generate 4 rows , 2 from the movie table and 2 from the movie copy table

MySQL LEFT JOIN?

I have a table cars(id, name) containing 20 rows. The other table carLog(username, car, count) contains rows which count the cars a player has bought (if there is no row if they haven't bought the car)
I want my query to return all twenty cars, and the extra join info, if they've got a row in the carLog table but I can't get it to work.
SELECT * FROM cars LEFT JOIN carLog ON cars.id=carLog.car
This is returning hundreds of rows, I want it to return 20 rows (one for each car), and the extra info in the row if the username has purchased the car:
WHERE carLog.username='Juddling'
I have no idea if I'm meant to be using GROUP BY, WHERE or another type of join!
Move the username condition from the WHERE clause to the ON clause.
SELECT *
FROM cars
LEFT JOIN carLog
ON cars.id=carLog.car
AND carLog.username='Juddling'
The WHERE clause is applied when the JOIN is already completed. This means, it will discard the NULL rows that the LEFT JOIN added.
As you are limiting the table from the outer join, you have to put the condition in the on, not the where:
select * from cars
left join carLog on cars.id = carLog.car and carlog.username = 'Juddling'