How to count GROUP BY rows in T-SQL - sql

I have this SQL query that does a GROUP BY to merge together all rows that contain the same Player_id but not the same Game_id:
SELECT p.Player_id,
p.Name,
p.Position,
SUM(s.Goals) AS goalsb,
SUM(s.Assists) AS assistsb,
SUM(s.Points) AS pointsb
FROM Dim_Player AS p
INNER JOIN Fact_Statistics AS s ON s.Player_id = p.Player_id
GROUP BY p.Player_id, p.Name, p.Position
ORDER BY pointsb DESC, goalsb DESC
What I want to do is implant a COUNT each time the GROUP BY merges a row with another to create a new column called "Games played". Example:
Player_id Game_id goalsb
8470598 465 1
8470598 435 1
this will be grouped together with the SQL query above to become:
Player_id goalsb
8470598 2
But I want to have this:
Player_id goalsb Games_played
8470598 2 2

If you have repeating Game_id's and you'd like to count the distinct values, you can add a
COUNT (DISTINCT Game_id)
clause to your SELECT statement.

Add a count function to the select query. COUNT(*) counts each row in the group, independent of the columns selected.
SELECT p.Player_id, p.Name, p.Position, SUM(s.Goals) AS goalsb, SUM(s.Assists) AS assistsb, SUM(s.Points) AS pointsb, COUNT(*) as [Games_played]
FROM Dim_Player AS p INNER JOIN Fact_Statistics AS s ON s.Player_id = p.Player_id
GROUP BY p.Player_id, p.Name, p.Position, s.Game_id
ORDER BY pointsb DESC, goalsb DESC

Related

Shorten a query

I have to write a query that would calculate number of tickets purchased consisting only of movie genre of that type. At the end, I have to return movie genre and number of tickets bought for that genre. I have written a query but I was wondering if it can be made shorter and more compact?
Following is the database scheme:
movies(movieId, movieGenre, moviePrice)
tickets(ticketId, ticketDate, customerId)
details(ticketId, movieId, numOfTickets)
Here is my query:
select m.genre, count(*)
from(select t.ticketId, m.genre
from(select d.ticketId
from(select m.genre, t.ticketId
from tickets t join details d on t.ticketId =
d.ticketId join movies m on d.movieId = m.movieId
group by m.genre, t.ticketId) d
group by d.ticketId
having count(*) = 1) as t join details d on t.ticketId =
d.ticketId join movies m on d.movieId = m.movieId
group by t.ticketId, m.genre) m
group by m.genre;
This runs on a database so I am only able to post sample output:
comedy 29821
action 27857
rom-com 19663
I see no reason to use the table tickets, because the results do not filter or aggregate by ticketDate or customerID. Thus, a shorter sql is
SELECT m.moviegenre,
Sum(d.numoftickets) as SumNum
FROM details d
LEFT JOIN movies m
ON d.movieid = m.movieid
GROUP BY m.moviegenre
HAVING SumNum > 0
ORDER BY m.moviegenre
added 3/28 am
I am not sure what is meant by Duplicates?? In table = details(ticketId, movieId, numOfTickets) ??
I would expect that ticketId is unique, so what would explain duplicates?
Is the same ticketId being printed twice, repeatedly??
Determine what number of ticketId are duplicates--
SELECT ticketId, count(*) as cnt
FROM details d
GROUP By ticketId
HAVING count(*) > 1
Determine what number of "details" rows are duplicates--
SELECT ticketId, movieId, numOfTickets, count(*) as cnt
FROM details d
GROUP By ticketId, movieId, numOfTickets
HAVING count(*) > 1
Then again, it may be that table = movies(movieId, movieGenre, moviePrice) is the one with duplicates??
Determine what number of movieId are duplicates--
SELECT movieId, count(*) as cnt
FROM movies m
GROUP BY movieId
HAVING count(*) > 1
Remove duplicates from details--
SELECT m.moviegenre,
Sum(d.numoftickets) as SumNum
FROM
(Select Distinct * From details) d
LEFT JOIN movies m
ON d.movieid = m.movieid
GROUP BY m.moviegenre
ORDER BY m.moviegenre

GROUP BY clause does not return winner in each group ID

I am trying to return the winner player in each group id, however, the group by function doesnt seem to work. Will appreciate your input on this.
SELECT
group_id,
player_id AS winner_id
FROM players AS p
LEFT JOIN (
SELECT
sum(first_score) AS total_first,
first_player
FROM matches
GROUP BY first_player
) AS a
ON p.player_id = a.first_player
LEFT JOIN (
SELECT
sum(second_score) as total_second,
second_player
FROM matches
GROUP BY second_player
) AS b
ON p.player_id = b.second_player
GROUP BY p.group_id
ORDER BY
coalesce(total_first, 0) + coalesce(total_second, 0) DESC,
player_id ASC
in your query no aggregate function so no need group by just use distinct
select distinct group_id, player_id as winner_id
from players as p
left join
(SELECT sum(first_score) as total_first, first_player
from matches
group by first_player) as a
on p.player_id = a.first_player
left join
(SELECT sum(second_score) as total_second, second_player
from matches
group by second_player) as b
on p.player_id = b.second_player
order by coalesce(total_first,0)+coalesce(total_second,0) desc, player_id asc
Assuming you want to have each field in levels of grouping, this may be a solution:
SELECT
group_id,
player_id AS winner_id
FROM players AS p
LEFT JOIN (
SELECT
sum(first_score) AS total_first,
first_player
FROM matches
GROUP BY first_player
) AS a
ON p.player_id = a.first_player
LEFT JOIN (
SELECT
sum(second_score) as total_second,
second_player
FROM matches
GROUP BY second_player
) AS b
ON p.player_id = b.second_player
GROUP BY
p.group_id,
p.player_id
ORDER BY
coalesce(total_first, 0) + coalesce(total_second, 0) DESC,
player_id ASC
When using GROUP BY you must specify sequence of all fields in grouping, so the statement is not ambiguous.
If I understand correctly, you want to sum the first and second score for each player, and then choose the one that has the highest value for the group.
So:
SELECT DISTINCT ON (p.group_id) p.group_id, v.player, SUM(score)
FROM matches m CROSS JOIN LATERAL
(VALUES (first_player, first_score),
(second_player, second_score)
) v(player, score) JOIN
players p
ON p.player_id = v.player
GROUP BY p.group_id, v.player
ORDER BY p.group_id, SUM(score) DESC;
Note that your LEFT JOIN approach is dangerous, because there might be some player, some time, some where, who is never first but always second.

How to find least group of students

I have this tables:
Student - Id, FirstName, LastName, Age
Group - Id, Name
Student_Group - Student_Id, Group_Id
I need to find least group of student. I have tried many times. I would be so glad if somebody helped.
Have you tried to do
SELECT top 1 g.name
FROM group g INNER JOIN Student_group sg ON g.id = sg.Group_Id
WHERE count(sg.student_id) >0
ORDER BY count(sg.student_id)
GROUP BY sg.group_id
?
If you want also the groups with 0 students you should to do
SELECT top 1 g.name
FROM group g INNER JOIN Student_group sg ON g.id = sg.Group_Id
ORDER BY count(sg.student_id)
GROUP BY sg.group_id
--If you just need the group with the least members,
--Group By and Count will work to find the Group with the least members
--Then use select top 1 record and order by GroupCount Ascending
SELECT TOP 1 Group_Id, COUNT(Group_Id) AS [GroupCount]
FROM Student_Group
GROUP BY Group_Id
ORDER BY [GroupCount]

SQL JOIN COUNT and GROUP BY

I have three tables
1. players(id, first_name, last_name, age, position, team_id)
2. teams(id, team_name, stadium, wins, draws,defeats,goal_for,goal_against)
3. goals_scored(id, player_id, goal_time)
SQL statement
SELECT
players.first_name,
players.last_name,
teams.name,
players.position,
players.age,
COUNT(*) AS goals
FROM
players
JOIN goals_scored
ON players.id = goals_scored.player_id
JOIN teams
ON players.team_id = teams.id
GROUP BY players.id;
teams table
id team_name stadium wins draws defeats goal_for goal_against
1 APF Club Dasharath 7 2 7 29 25
players table
id first_name last_name position age team_id
4 Dipendra Shrestha forward 19 1
goals_scored table
id player_id goal_time
1 4 34
2 4 57
I want to group goals on players id so that I can get the count of goals of an individual player.
Like
first_name last_name team_name position age goals
Dipendra Shrestha APF Club forward 19 2
How can I do it?
Prefer to group on as few as possible columns, especially if multiple tables get involved so that a good index can be applied to handle the group by.
WITH GoalsPerPlayer (playerId, nrOfGoals)
AS
(
SELECT player_id, count(*)
FROM goals_scored
GROUP BY player_id
)
SELECT p.first_name, p.last_name, t.team_name, p.position, p.age, g.numberOfGoals as goals
FROM GoalsPerPlayer g
INNER JOIN players p ON p.id = g.player_id
INNER JOIN teams t ON t.id = p.team_id
Edit:
Fixed typo's in query as mentioned by PO in comment below.
WITH GoalsPerPlayer (playerId, nrOfGoals)
AS
(
SELECT player_id, count(*)
FROM goals_scored
GROUP BY player_id
)
SELECT p.first_name, p.last_name, t.team_name, p.position, p.age, g.nrOfGoals as goals
FROM GoalsPerPlayer g
INNER JOIN players p ON p.id = g.playerId
INNER JOIN teams t ON t.id = p.team_id
Your query basically looks fine. I would adjust the GROUP BY to be more complete:
SELECT p.first_name, p.last_name, t.name, p.position, p.age,
COUNT(*) AS goals
FROM players p JOIN
goals_scored gs
ON p.id = gs.player_id JOIN
teams t
ON p.team_id = t.id
GROUP BY p.first_name, p.last_name, t.name, p.position, p.age;

Help with SQL QUERY OF JOIN+COUNT+MAX

I need a help constructung an sql query for mysql database. 2 Table as follows:
tblcities (id,name)
tblmembers(id,name,city_id)
Now I want to retrieve the 'city' details that has maximum number of 'members'.
Regards
SELECT tblcities.id, tblcities.name, COUNT(tblmembers.id) AS member_count
FROM tblcities
LEFT JOIN tblmembers ON tblcities.id = tblmembers.city_id
GROUP BY tblcities.id
ORDER BY member_count DESC
LIMIT 1
Basically: retrieve all cities and count how many members each has, sort by that member count in descending order, making the highest count first - then show only that first city.
Terrible, but that's a way of doing it:
SELECT * FROM tblcities WHERE id IN (
SELECT city_id
FROM tblMembers
GROUP BY city_id
HAVING COUNT(*) = (
SELECT MAX(TOTAL)
FROM (
SELECT COUNT(*) AS TOTAL
FROM tblMembers
GROUP BY city_id
) AS AUX
)
)
That way, if there is a tie, still you'll get all cities with the maximum number of members...
Select ...
From tblCities As C
Join (
Select city_id, Count(*) As MemberCount
From tblMembers
Order By Count(*) Desc
Limit 1
) As MostMembers
On MostMembers.city_id = C.id
select top 1 c.id, c.name, count(*)
from tblcities c, tblmembers m
where c.id = m.city_id
group by c.id, c.name
order by count(*) desc