How do I use MAX and Count with two table - sql

I have a query that needs to count the field Points. Then returns the highest value. This query does that fine however I now want to link another table 'Team(PlayerID) with Player(PlayerID), So it shows the player team details etc. I attempted to do that normally on how you would join table but keep getting errors. I also do not want to use the order by desc - First row only. (Oracle)
Query:
SELECT PlayerID, COUNT(Points)

SELECT t.*, p.* FROM
team t INNER JOIN
(SELECT PlayerID, COUNT(Points)
FROM Player
WHERE Points = 1
group by PlayerID
HAVING COUNT(Points) = (SELECT MAX(count(Points))
from Player
WHERE Points = 1
group by PlayerID)
) p
ON t.PlayerID = p.PlayerID

....
HAVING COUNT(Points) = (SELECT MAX(sub.cp)
from (SELECT count(Points) as cp
from Player
WHERE Points = 1
group by PlayerID) sub
)

SELECT A.PlayerID, a.TotalPoints, b.[stuff]
FROM (SELECT PlayerID, COUNT(Points)
FROM Player
WHERE Points = 1
group by PlayerID
HAVING COUNT(Points) = (SELECT MAX(count(Points))
from Player
WHERE Points = 1
group by PlayerID)) a
join TEAM b on b.playerid = a.playerid;

Related

SQL Server stored procedure - Is it possible to return multiple results within a field of each row

I am wondering if it's possible to return multiple results within a column of each row or the best way to get multiple results within a column.
Example if you have a stored procedure that will return multiple students, but one of the columns within the student table is the photo id. A student can have several photos, but this stored procedure needs to return all three photo ids for each student.
SELECT
S.Name AS Name,
(SELECT S.Id FROM COURSES WHERE P.StudentId = S.Id) AS PhotoId
FROM
PHOTOS P
INNER JOIN
PHOTOS P ON P.StudentId = S.Id
The example above will not work, but I need to know what is the best way of doing it. As the maximum number of pictures is set to 3, I was thinking to create each photo id within a separate column such as the following.
SELECT
S.Name AS Name,
(SELECT TOP 1 S.Id FROM COURSES WHERE P.StudentId = S.Id) AS PhotoId1,
(SELECT TOP 2 S.Id FROM COURSES WHERE P.StudentId = S.Id) AS PhotoId2,
(SELECT TOP 3 S.Id FROM COURSES WHERE P.StudentId = S.Id) AS PhotoId3
FROM
PHOTOS P
INNER JOIN
PHOTOS P ON P.StudentId = S.Id
In this case only the top line would work. Instead of using TOP 2 and TOP 3 what is the equivalent of taking taking only the second and third result (same as in Linq Take(1) and Skip(1)).
Or is there a better way of doing it? Also I must make sure each student is only returned once even if they have multiple images
I am uncertain which way you are hoping to structure your data with photos in a row or photos in separate columns. However, Rows seem more natural to me.
Rows
SELECT ph.Name
, PhotoId = co.Id
FROM dbo.Photos (NOLOCK) ph
JOIN dbo.Courses (NOLOCK) co ON co.Id = ph.StudentId
Output:
Name | PhotId
Edward | 1234
Edward | 2345
Edward | 3456
Updated
Columns
;WITH CTE AS(
SELECT ph.Name
, PhotoId = co.Id
, RN = ROW_NUMBER()OVER(PARTITION BY ph.Name ORDER BY co.Id)
FROM dbo.Photos (NOLOCK) ph
JOIN dbo.Courses (NOLOCK) co ON co.Id = ph.StudentId
)
SELECT Name
, PhotoId1 = SUM(CASE WHEN RN = 1 THEN Id ELSE NULL END)
, PhotoId2 = SUM(CASE WHEN RN = 2 THEN Id ELSE NULL END)
, PhotoId3 = SUM(CASE WHEN RN = 3 THEN Id ELSE NULL END)
FROM CTE
GROUP BY Name
Try this using row_number to get 1, 2 and 3 photos
SELECT S.Name AS Name
,(select x.photo_id from (SELECT PHOTO_ID, row_number() over (order by photo_id) row_num from PHOTOS P where p.student_id = s.studenT_id) x where x.row_num = 1) AS PhotoId1
,(select x.photo_id from (SELECT PHOTO_ID, row_number() over (order by photo_id) row_num from PHOTOS P where p.student_id = s.studenT_id) x where x.row_num = 2) AS PhotoId2
,(select x.photo_id from (SELECT PHOTO_ID, row_number() over (order by photo_id) row_num from PHOTOS P where p.student_id = s.studenT_id) x where x.row_num = 3) AS PhotoId3
FROM STUDENTS S

Highest Count with a group

I'm having an absolute brain fade
SELECT p.ProductCategory, f.ProductSubCategory, COUNT(*) AS Cnt
FROM Sales f
JOIN Products p ON f.ProductSubCategory = p.ProductSubCategory
GROUP BY p.ProductCategory, f.ProductSubCategory
ORDER BY 1,3 DESC
This shows me the count for each ProductSubCategory, I would like to see only the highest ProductSubCategory per ProductCategory.
I wish to see (I don't care about the Count value)
There are a couple of different ways to do this. One involves joining the results back to themselves and using the max aggregate. But since you are using SQL Server, you can use ROW_NUMBER to achieve the same result:
with cte as (
select p.productcategory, p.ProductSubCategory, COUNT(*) cnt,
ROW_NUMBER() over (partition by p.productcategory order by count(*) desc) rn
from products p
join sales s on p.ProductSubCategory = s.ProductSubCategory
group by p.productcategory, p.ProductSubCategory
)
select *
from cte
where rn = 1
You already got the answer, Please see the following code to. It may help you.
SELECT p.ProductCategory,
f.ProductSubCategory,
COUNT(*) AS Cnt
FROM Sales f
JOIN Products p ON f.ProductSubCategory = p.ProductSubCategory
JOIN (
SELECT p.ProductCategory,
f.ProductSubCategory,
ROW_NUMBER() OVER ( PARTITION BY p.ProductCategory,
f.ProductSubCategory
ORDER BY COUNT(*) DESC) [Row]
FROM Sales f
JOIN Products p ON f.ProductSubCategory = p.ProductSubCategory) Lu
ON P.ProductCategory = Lu.ProductCategory
AND f.ProductSubCategory = Lu.ProductSubCategory
WHERE Lu.Row = 1
GROUP By p.ProductCategory,
f.ProductSubCategory

SQL Sum of rows grouped by id

This SQL:
select Name,
(select COUNT(1) from tbl_projects where statusId = tbl_sections.StatusId) as N
from tbl_sections
left join tbl_section_names on tbl_section_names.Id = NameId
Generates the follows data:
Name N
Completed 133
Cancelled 100
Unassigned 1
Sales 49
Development 10
Development 4
Development 1
I'm trying to modify it so it returns the data as follows:
Name N
Completed 133
Cancelled 100
Unassigned 1
Sales 49
Development 15
(ie, sum up the rows where the name is the same)
Can anyone suggest some clues on how to make this work ? I'm guessing I need a SUM and a GROUP BY, but it never even runs the query as all I get are errors.
Try this query. It sums N grouped by Name.
SELECT Name, SUM(N)
FROM (
SELECT Name,
(SELECT COUNT(1)
FROM tbl_projects
WHERE statusId = tbl_sections.StatusId
) AS N
FROM tbl_sections
LEFT JOIN tbl_section_names ON tbl_section_names.Id = NameId
) a
GROUP BY a.Name
Try this
select Name, count(p.statusid) N
from tbl_sections
left join tbl_section_names on tbl_section_names.Id = NameId
left outer join tbl_projects p on tbl_sections.StatusId = p.statusId
group by Name
Select Name, Sum(N) from
(select Name,
(select COUNT(1) from tbl_projects where statusId = tbl_sections.StatusId) as N
from tbl_sections
left join tbl_section_names on tbl_section_names.Id = NameId)
group by Name
This query is giving you count per status, which means Development has sections with three different status's, and the query would reflect this and make more sense if you added the status as a column:
select Name, tbl_sections.StatusId,
(select COUNT(1) from tbl_projects where statusId = tbl_sections.StatusId) as N
from tbl_sections
left join tbl_section_names on tbl_section_names.Id = NameId
I don't know the structure of your database, but I if you want a count of the number of sections per name, might be like this. This basically will look at the result of the join, and then summarize it by telling you the number of times each unique name occurs:
select Name, count(*)
from tbl_sections
left join tbl_section_names on tbl_section_names.Id = NameId
Group By Name
Try and give this a go.
select Name,
SUM(select COUNT(1) from tbl_projects where statusId = tbl_sections.StatusId) as N
from tbl_sections
left join tbl_section_names on tbl_section_names.Id = NameId
group by Name

How to get a master table record by count of detail table records without top(1)

I have a master table (Team) and a detail table (TeamMember). TeamMember has a FK to Team.
I need to get the Team record for the team that has the most team members. I at first had
SELECT team.name
FROM team
INNER JOIN (SELECT TOP 1 COUNT(*) AS membercount,
teamID
FROM teammember
GROUP BY teamID
ORDER BY Count(*) DESC) AS team_with_most_members
ON team.id = team_with_most_members.teamID
I was informed that I cannot use TOP(1) in my queries. Anyone have an idea how I can do it without?
Thanks!
Team
ID, Name
TeamMember
ID, TeamID, UserID
This one is crude but it works:
SELECT t.name
FROM team AS t
JOIN teammember AS tm ON tm.teamID = t.ID
GROUP BY t.Name
HAVING COUNT(tm.id) = (SELECT MAX(members) FROM (SELECT COUNT(id) members FROM teammember GROUP BY teamid) AS sub)
This makes me feel dirty. It will return a single team name even if there is a tie - if you want all rows in the event of a tie, use DENSE_RANK() instead of ROW_NUMBER().
SELECT t.ID, t.Name FROM
(
SELECT
TeamID, rn = ROW_NUMBER() OVER (ORDER BY c DESC)
FROM
(
SELECT TeamID, c = COUNT(*)
FROM dbo.TeamMember GROUP BY TeamID
) AS x
) AS y
INNER JOIN dbo.Team AS t
ON y.TeamID = t.ID
WHERE y.rn = 1; -- **EDIT** forgot the most important part!
I'd really stand up and challenge the "no TOP 1" rule. Ask the person who told you it was for performance reasons to compare the performance of your existing query with any of the kludges we've come up with.
TOP 1 is cleanest way. Here's a really convoluted way that might work:
SELECT ID FROM (
SELECT ID, Tally, MAX(Tally) over (partition by ID) AS MaxTally
FROM (SELECT t1.ID,
COUNT(t2.ID) AS Tally
FROM #Team t1
JOIN #TeamMember t2
ON t2.TeamID = t1.ID
GROUP BY t1.ID) x
) y WHERE Tally = MaxTally

How to count number of different items in SQL

Database structure:
Clubs: ID, ClubName
Teams: ID, TeamName, ClubID
Players: ID, Name
Registrations: PlayerID, TeamID, Start_date, End_date, SeasonID
Clubs own several teams. Players may get registered into several teams (inside same club or into different club) during one year.
I have to generate a query to list all players that have been registered into DIFFERENT CLUBS during one season. So if player swapped teams that were owned by the same club then it doesn't count.
My attempts so far:
SELECT
c.short_name,
p.surname,
r.start_date,
r.end_date,
(select count(r2.id) from ejl_registration as r2
where r2.player_id=r.player_id and r2.season=r.season) as counter
FROM
ejl_registration AS r
left Join ejl_players AS p ON p.id = r.player_id
left Join ejl_teams AS t ON r.team_id = t.id
left Join ejl_clubs AS c ON t.club_id = c.id
WHERE
r.season = '2008'
having counter >1
I can't figure out how to count and show only different clubs... (It's getting too late for clear thinking). I use MySQL.
Report should be like: Player name, Club name, Start_date, End_date
This is a second try at this answer, simplifying it to merely count the distinct clubs, not report a list of club names.
SELECT p.surname, r.start_date, r.end_date, COUNT(DISTINCT c.id) AS counter
FROM ejl_players p
JOIN ejl_registration r ON (r.player_id = p.id)
JOIN ejl_teams t ON (r.team_id = t.id)
JOIN ejl_clubs c ON (t.club_id = c.id)
WHERE r.season = '2008'
GROUP BY p.id
HAVING counter > 1;
Note that since you're using MySQL, you can be pretty flexible with respect to columns in the select-list not matching columns in the GROUP BY clause. Other brands of RDBMS are more strict about the Single-Value Rule.
There's no reason to use a LEFT JOIN as in your example.
Okay, here's the first version of the query:
You have a chain of relationships like the following:
club1 <-- team1 <-- reg1 --> player <-- reg2 --> team2 --> club2
Such that club1 must not be the same as club2.
SELECT p.surname,
CONCAT_WS(',', GROUP_CONCAT(DISTINCT t1.team_name),
GROUP_CONCAT(DISTINCT t2.team_name)) AS teams,
CONCAT_WS(',', GROUP_CONCAT(DISTINCT c1.short_name),
GROUP_CONCAT(DISTINCT c2.short_name)) AS clubs
FROM ejl_players p
-- Find a club where this player is registered
JOIN ejl_registration r1 ON (r1.player_id = p.id)
JOIN ejl_teams t1 ON (r1.team_id = t1.id)
JOIN ejl_clubs c1 ON (t1.club_id = c1.id)
-- Now find another club where this player is registered in the same season
JOIN ejl_registration r2 ON (r2.player_id = p.id AND r1.season = r2.season)
JOIN ejl_teams t2 ON (r2.team_id = t2.id)
JOIN ejl_clubs c2 ON (t2.club_id = c2.id)
-- But the two clubs must not be the same (use < to prevent duplicates)
WHERE c1.id < c2.id
GROUP BY p.id;
Here's a list of players for one season.
SELECT sub.PlayerId
FROM
(
SELECT
r.PlayerId,
(SELECT t.ClubID FROM Teams t WHERE r.TeamID = t.ID) as ClubID
FROM Registrations r
WHERE r.Season = '2008'
) as sub
GROUP BY PlayerId
HAVING COUNT(DISTINCT sub.ClubID) > 1
Here's a list of players and seasons, for all seasons.
SELECT PlayerId, Season
FROM
(
SELECT
r.PlayerId,
r.Season,
(SELECT t.ClubID FROM Teams t WHERE r.TeamID = t.ID) as ClubID
FROM Registrations r
) as sub
GROUP BY PlayerId, Season
HAVING COUNT(DISTINCT sub.ClubID) > 1
By the way, this works in MS SQL.
SELECT p.Name, x.PlayerID, x.SeasonID
FROM (SELECT DISTINCT r.PlayerID, r.SeasonID, t.ClubID
FROM Registrations r
JOIN Teams t ON t.ID = r.TeamID) x
JOIN Players p ON p.ID = x.PlayerID
GROUP BY p.rName, x.PlayerID, x.SeasonID
HAVING COUNT(*) > 1