MySQL view subquery with custom where clause? - mysql

I am trying to design a view on a MySQL database that stores information about football (soccer).
My goal is to create a view that returns all the goals and the basic information of the scorers. This is a simplified version of what the view used to look like:
SELECT P.Name AS Player,
P.TeamName AS Team,
(SELECT COUNT(*)
FROM Goals G
WHERE G.Scorer = P.playerID) AS TotalGoals
FROM Players P
So far, everything's right. The problem started when I wanted to count goals only within a certain season, specified in the WHERE clause, as I show below:
SELECT * FROM GoalsView WHERE Season = 1
And for it to return automatically only the count of the goals of the season in WHERE clause, as if the subquery was automatically edited to make it look like:
[...]
(SELECT COUNT(*)
FROM Goals G
WHERE G.Scorer = P.playerID
AND Season=1) AS TotalGoals
[...]
I hope I made myself clear. Thanks for your help!

One possible solution is
SELECT P.Name AS Player,
P.TeamName AS Team,
(SELECT COUNT(*)
FROM Goals G
WHERE G.Scorer = P.playerID AND season=1 GROUP By season) AS TotalGoals
FROM Players P
I don't know whether you have separate table for season or a column

In order to have access to goals.season, you must join the two tables:
select
p.name as player,
p.teamname as team,
count(goals.id) as totalgoals
from players p
left join goals g on g.scorer = p.playerid
group by p.name, p.teamname;

Related

How do add data to multiple columns at the same time

I got this last task before I can go to bed...
Make a query that shows the name(not the id) of players who have won the lottery more than once, how many times they've won and the name(not the id) of the municipality they live in.
Players-table: PlayerNum, Name, Address, MunicipalityID
Winners-table: PlayerNum, DrawID
Municipality-table: MunicipalityID, County, Population, Name
Thank you sooo much in advance!!
You need to join the tables and do a sub query on the winner table using count and group by the join the result set with player
Not sure what the draw table does
You really should make an attempt instead of just asking for the solution.
Your starting point is to find the users who have won more than once. This is a simple GROUP BY of PlayerNum and the HAVING clause to limit the result based on the COUNT -
SELECT PlayerNum, COUNT(DrawID) AS num_wins
FROM Winners
GROUP BY PlayerNum
HAVING num_wins > 1
The next step is to add the names of the players. For this you need to join to the Players table and I have added table aliases (w & p) to avoid retyping the full table name each time -
SELECT p.Name, COUNT(DrawID) AS num_wins
FROM Winners w
INNER JOIN Players p
ON w.PlayerNum = p.PlayerNum
GROUP BY w.PlayerNum
HAVING num_wins > 1
And then finally the join to Municipality to get the Name with a column alias as we already have a Name column -
SELECT p.Name, COUNT(DrawID) AS num_wins, m.Name AS MunName
FROM Winners w
INNER JOIN Players p
ON w.PlayerNum = p.PlayerNum
INNER JOIN Municipality m
ON p.MunicipalityID = m.MunicipalityID
GROUP BY w.PlayerNum
HAVING num_wins > 1

top 10 scorers by season

How I can get top 10 scorers by seasons.
So it shows last season top 10 scorers...
I've tryed left join into table, but it goes broken showing 2 player and counts all goals to first player.
My sqlfiddle:
http://sqlfiddle.com/#!9/b5d0a78/1
You got it almost right.
You want to group match_goals by player ID (match_player_id), but then you should not select goal_minute or any other per goal data.
After grouping by player, then you can create a column for COUNT(match_player_id) this will give you the number of goals, you can also use this column to order the results.
Your joins and conditions are correct I think.
EDIT
I think your schema needs a few tweaks: check this http://sqlfiddle.com/#!9/f5a75b/2
Basically create direct relations in the match_players and match_goals to the other tables.
I think the query you want looks like this:
SELECT p.*, count(*) as num_goals
FROM match_goals g INNER JOIN
match_players p
ON g.match_player_id = p.id INNER JOIN
matches m
ON m.id = p.match_id
WHERE p.is_deleted = 0 AND
g.is_own_goal = 0 AND
m.seasion_id = <last season id>
GROUP BY p.id
ORDER BY num_goals DESC
LIMIT 10;
Note that the teams table is not needed. The SELECT p.* is allowed because p.id (the GROUP BY key) is unique.

Good alternatives of comporting two subquery in the 'Where' clause

I have this schema:
CLUB(Name, Address, City)
TEAM(TeamName, club)
PLAYER(Badge, teamName)
MATCH(matchNumber, player1, player2, club, winner)
I need to make this query:
For each club, find the number of players in that club that have won
at least two games.
I wrote this:
SELECT teamName
From TEAM t join Match m1 on t.club=m1.club
WHERE Q2 >= ALL Q1
Q1:
SELECT Count (Distinct winner)
FROM MATCH
WHERE match m join player p on m. winner=player.badge
GROUP BY teamName
Q2:
SELECT Count (distinct winner)
FROM match m2
WHERE m2.club=m1.club
I don’t know if it is correct, however I heard that using this form where I confront two counts is not the best. Why?
Try something like this:
SELECT club, COUNT(*) as PlayerCount
FROM (SELECT club, winner
FROM match
GROUP BY club, winner
HAVING COUNT(*) > 1) a
GROUP BY club
The inner query should limit results to club/player combinations that have 2 or more wins, and the outer query will count the number of these players per club.
I don’t know if it is correct, however I heard that using this form where I confront two counts is not the best. Why?
Comparing two count subqueries is fine if you need to, but a good rule of thumb is to hit each table as few times as possible. Using multiple subqueries will end up hitting each table multiple times, and will usually result in longer execution times.
Try this query
SELECT t.club, COUNT(*)
FROM TEAM t
JOIN PLAYER p ON p.teamName = t.TeamName
JOIN (
-- Won at least 2 matches.
SELECT club, winner, COUNT(*) AS TheCount
FROM MATCH
GROUP BY club, winner
HAVING COUNT(*) > 1
) w ON w.winner = p.badge AND w.club = t.club
GROUP BY t.club

Removing an item from the result if it has a particular parameter somewhere in the table

I've been looking all around stack overflow and can't seem to find a question like this but its probably super simple and has been asked a million times. So I am sorry if my insolence offends you guys.
I want to remove an attribute from the result if it appears anywhere in the table.
Here is an example: I want display every team that does not have a pitcher. This means I don't want to display 'Phillies' with the rest of the results.
Example of table:
Here is the example of the code I have currently have where Players is the table.
SELECT DISTINCT team
FROM Players
WHERE position ='Pitcher' Not IN
(SELECT DISTINCT position
FROM Players)
Thanks for any help you guys can provide!
You can use NOT EXISTS() :
SELECT DISTINCT s.team
FROM Players s
WHERE NOT EXISTS(SELECT 1 FROM Players t
where t.team = s.team
and position = 'Pitcher')
Or with NOT IN:
SELECT DISTINCT t.team
FROM Players t
WHERE t.team NOT IN(SELECT s.team FROM Players s
WHERE s.position = 'Pitcher')
And a solution with a left join:
SELECT distinct t.team
FROM Players t
LEFT OUTER JOIN Players s
ON(t.team = s.team and s.position = 'pitcher')
WHERE s.team is null
Use NOT EXISTS
Query
select distinct team
from players p
where not exists(
select * from players q
where p.team = q.team
and q.position = 'Pitcher'
);
Probably the easiest way to approach this problem is to aggregate players over team:
select team
from players
group by team
having sum(case when position = 'Pitcher' then 1 else 0 end) = 0;
The big advantage is that you'd read the table only once.
Another advantage is that you can easily adjust the HAVING clause to have more elaborate queries, e.g. get all teams that have at least one catcher, two outfielders, and no pitcher.

MYSQL View and summing fields

I need some help I have been scouring the web and haven't been able to find something too similar. I have a MYSQL database for my Golf League. I need to display standings by creating a view from this database. There are 2 people per team, my primary key in 'players' is 'id' there is also a teamID (numerical value 1 - 20, 20 teams) for each player which corresponds to their teammates. Basically what I need is a view that contains 'teamID', both players 'LName' (maybe an 'LNameA','LNameB'), and a sum of the two players 'points' field. I have never summed a field from one person and another or created a view in MYSQL.
EDIT:
I was trying something like
CREATE
VIEW standings1
AS SELECT teamID, LName, points
FROM players
but need teamID to be the primaryKey of the view which will contain each players last name, and their points summed together.
Try this:
create view standings as
select teamId, group_concat(lname separator ', ') as TeamMembers,
sum(points) TotalPoints from players
group by teamId
Oh, one more thing. If you want to have the names of the players in different fields (group_concat just separate them by commas, but it is still a single field) you can use this query:
create view standings as
select a.teamId, a.lname as player1, b.lname as player2,
a.points + b.points TotalPoints
from players a
join players b ON a.teamId = b.teamId AND a.id >= b.id
group by a.teamId, a.id
having count(*) = 2
That way you can play better with the names in PHP without having to parse the ", "
If I understand your table structure, you will need a JOIN against the table's own teamID. I'm assuming the teamID refers to a team, and is not the id of the player. The trick here is to join two copies of the table on the same teamID, but where the player ids are non-equal. That should produce the pair of players per team.
CREATE VIEW standings AS
(
SELECT
p1.teamID AS teamID,
p1.id AS p1id,
p2.id AS p2id,
p1.LName AS p1LName,
p2.LName AS p2LName,
p1.score + p2.score AS totalScore
FROM
/* JOIN on matching teamID and non-matching player-id (so you don't get the same player twice) */
players p1 JOIN players p2 ON p1.teamID = p2.teamID and p1.id <> p2.id
);