SQL aggregate query error - sql

I have 3 tables like this
player(id,name,age,teamid)
team(id,name,sponsor,totalplayer,totalchampion,boss,joindate)
playerdetail(id,playerid,position,number,allstar,joindate)
I want to select teaminfo include name,sponsor,totalplayer,totalchampion,boss,
the average age of the players, the number of the allstar players
I write the t-sql as below
SELECT T.NAME,T.SPONSOR,T.TOTALPLAYER,T.TOTALCHAMPION,T.BOSS,T.JOINDATE,
AVG(P.AGE) AS AverageAge,COUNT(D.ALLSTAR) As AllStarPlayer
FROM Team T,Player P,PlayerDetail D
WHERE T.ID=P.TID AND P.ID=D.PID
but it doesn't work, the error message is
'Column 'Team.Name' is invalid in the select list because it is not
contained in either an aggregate function or the GROUP BY clause.'
Who can help me?
Thx in advance!

Add
GROUP BY
T.NAME,T.SPONSOR,T.TOTALPLAYER,T.TOTALCHAMPION,T.BOSS,T.JOINDATE
In most RDBMS (except MySQL which will guess for you), a column must be either aggregated (COUNT, AVG) or in the GROUP BY
Also, you should use explicit JOINs.
This is clearer, less ambiguous and more difficult to bollix your code
SELECT
T.NAME, T.SPONSOR, T.TOTALPLAYER, T.TOTALCHAMPION, T.BOSS, T.JOINDATE,
AVG(P.AGE) AS AverageAge,
COUNT(D.ALLSTAR) As AllStarPlayer
FROM
Team T
JOIN
Player P ON T.ID=P.TID
JOIN
PlayerDetail D ON P.ID=D.PID
GROUP BY
T.NAME, T.SPONSOR, T.TOTALPLAYER, T.TOTALCHAMPION, T.BOSS, T.JOINDATE;

Given that you want this data per team, and team.ID uniquely identifies team, I suggest the following:
SELECT max(T.NAME) As TeamName,
max(T.SPONSOR) As Sponsor,
max(T.TOTALPLAYER) As TotalPlayers,
max(T.TOTALCHAMPION) As TotalChampions,
max(T.BOSS) As Boss,
max(T.JOINDATE) As JoinDate,
AVG(P.AGE) AS AverageAge,
COUNT(D.PID) As AllStarPlayer
FROM Team T
join Player P on T.ID=P.TID
left join PlayerDetail D on P.ID=D.PID and D.ALLSTAR = 'Y'
group by T.ID

Use:
SELECT T.NAME,T.SPONSOR,T.TOTALPLAYER,T.TOTALCHAMPION,T.BOSS,T.JOINDATE,
AVG(P.AGE) AS AverageAge,COUNT(D.ALLSTAR) As AllStarPlayer
FROM Team T
JOIN Player P ON T.ID = P.TEAMID
JOIN PlayerDetail D ON P.ID = D.PLAYERID
GROUP BY T.NAME,T.SPONSOR,T.TOTALPLAYER,T.TOTALCHAMPION,T.BOSS,T.JOINDATE

Related

Calculated Field Using Group By Subquery

I have one table which holds Lessons with theirs attributes such as DepId and FieldId. I have two tables also, about Lesson Departments and Lesson Fields. I need to calculate lesson's weekly times percentage's based on DepId and FieldId. My query as follows:
Select a.FieldName, b.DepName, sum(LessonWeeklyTime), ((sum(LessonWeeklyTime))*100)/(select LessonDep, sum(LessonWeeklyTime)
From Lessons
Group By LessonDep)
from Lessons l, Departments b, Fields a
Where l.LessonDep=b.DepId
And l.LessonField=a.FieldId
Group By b.DepName,a.FieldName
But I am getting error:
Msg 116, Level 16, State 1, Line 2
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
Appreciate for help.
Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax. It is the 21st Century, after all.
You should be doing this with window functions:
select f.FieldName, d.DepName, sum(LessonWeeklyTime),
(sum(LessonWeeklyTime) * 100.0 /
sum(sum(LessonWeeklyTime)) over (partition by d.depName)
from Lessons l join
Departments d
on l.LessonDep = d.DepId join
Fields f
on l.LessonField = f.FieldId
Group By d.DepName, f.FieldName
As the error message states, you may only have one column in your subquery. Try it that way:
Select a.FieldName, b.DepName, sum(LessonWeeklyTime), ((sum(LessonWeeklyTime))*100)/(select sum(LessonWeeklyTime)
From Lessons
Group By LessonDep)
from Lessons l, Departments b, Fields a
Where l.LessonDep=b.DepId
And l.LessonField=a.FieldId
Group By b.DepName,a.FieldName
Check this:
Select a.FieldName, b.DepName, sum(LessonWeeklyTime), ((sum(LessonWeeklyTime))*100)/ sum(c.LessonWeeklyTime)
from Lessons l, Departments b, Fields a ,(select LessonDep, sum(LessonWeeklyTime) LessonWeeklyTime
From Lessons
Group By LessonDep) c
Where l.LessonDep=b.DepId
And l.LessonField=a.FieldId
And l.LessonDep=c.LessonDep
Group By b.DepName,a.FieldName
This gets the time by necessary codes from 1 table and uses a window function for the percentage. It groups/calculates by the IDs rather than descriptions to improve performance and reduce chance of errors on poor labelling/nulls:
WITH CTE AS( SELECT LESSONDEP, LESSONFIELD, SUM(LESSONWEEKLYTIME) AS [TIME]
FROM [LESSONS]
GROUP BY LESSONDEP, LESSONFIELD)
SELECT F.FIELDNAME, D.DEPNAME, L.[TIME], (L.[TIME]*100.0) / (SUM(L.[TIME]) OVER (PARTITION BY L.LESSONDEP) AS [PERCENTAGE]
FROM CTE L
INNER JOIN DEPARTMENTS D ON L.LESSONDEP = D.DEPID
INNER JOIN FIELDS F ON L.LESSONFIELD = F.FIELDID

Use result of multiple rows to do arithmetic operation

I'm writing a query to multiply the count that I receive from subquery to fees amount, But I don't know how to do that. Any help/suggestion?
Oracle query is:
select courseid,coursename,fees*tmp
from course c join registration r on
r.courseid=c.courseid
and tmp IN (select count(*)
from course c join registration r on
r.courseid=c.courseid group by coursename);
I tried to use like a variable tmp ,But i don't think it works in oracle query. Is there an alternative way to do so?
You can't do that, because you can only select data from tables that appeared between FROM and WHERE. The IN operator is a quick way to save having to write a bunch of OR statements, it is not something that can establish a variable in the outer query.
Instead do something like:
select courseid,coursename,fees * COUNT(r.courseID) OVER(PARTITION BY c.coursename)
from course c join registration r on
r.courseid=c.courseid
Edit/update: you noted that this query produces too many rows and you only want to see distinct course names. In that case it would be better to just use the registrations table to count the number of people on the course and then multiply the fees:
SELECT
c.courseid, c.coursename, c.fees * COALESCE(r.numberOfstudents, 0) as courseWorth
FROM
course c
LEFT OUTER JOIN
(select courseid, COUNT(*) as numberofstudents FROM registration GROUP BY courseid) r
ON c.courseID = r.courseid
You can use a windowing function like Caius or you can use a join like this:
select courseid,coursename, fees * COALESCE(sub.cnt,0)
from course c
join registration r on r.courseid=c.courseid
left join (
select coursename, count(*) as cnt
from course c2
join registration r2 on r2.courseid=c2.courseid
group by coursename
) as sub;
note: I make no claim your joins are correct -- I'm basing this query off of your example not on any knowledge of your data model.

Count participants of tournament

i have schema like this http://sqlfiddle.com/#!17/30859/1, as you can see in that SQL fiddle i have query that i need to improve, actually i need to add new column that will give me total number of participants in each tournament, i'm not sure how i can do that, i tried sub select but without any success. Thanks in advance for help
SELECT t.id, t.name as tournamentName, m.name as creator, s.name as
sponsorName,
(count * from member_tournament mt where mt.tournament_id=t.id) members
FROM tournament t
LEFT JOIN member m ON m.id = t.member_id
LEFT JOIN sponsor s ON s.id = t.sponsor_id

SQL substraction

I have two tables:
Teams (Name, Team ID, Max Size)
Members (Name, Team ID)
I need to figure out out how many slots are available on each team. The closest I got was counting occurrences in Name and grouping by Team ID in the Members table, but after that I have no idea how to subtract Max Size by the count_of_Name. I understand this is a rudimentary question, but I assure you I have been working and researching this question for well over an hour. Thank you in advance.
No subqueries needed:
select t.[Team ID], t.Name, t.MaxSize - COUNT(m.*) as SpotsLeft
from Teams t
left join Members m on m.[Team ID] = t.[Team ID]
group by t.[Team ID], t.Name, t.MaxSize
You could achieve this with a subquery :
select (select max(count(*))
from teams
join members using(teamId)
group by teamId) - count(members.*) as available_slots
from teams
join members using(teamId);
Note that it would be a lot easier if the maximum possible member per teams would be fixed as you could directly substract instead of using a subquery.
SELECT t.MaxSize - (SELECT COUNT(*)
FROM Members m
WHERE m.team_id = t.team_id)
FROM Teams t
Or, to avoid (multiple) sub-queries
SELECT t.MaxSize, q.Team_Count
FROM Teams t
LEFT JOIN (SELECT m.Team_ID, COUNT(*) as Team_Count
FROM Members m
GROUP BY m.Team_ID) as q
ON q.Team_ID = t.Team_ID

SQL Beginner - How to get items from Table1 that are associated with at least 10 items in Table2

This is probably very easy, but I'm confused after looking at things online. Each item in my Contract table has multiple Envelopes. I want to find Contracts that have at least 10 envelopes. How do I go about this?
I've tried the following
select c.*, COUNT(e.ID)
from [Contract] c
INNER JOIN Envelope e ON e.ContractID = c.ID
Group By c.ID
HAVING Count(e.ID) > 10
And I get
Column 'Contract.PresenterUserID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I haven't dealt with aggregate or group by clauses before, so I'm not sure what it means.
By default, MySQL will accept your query. So, I am assuming that you are not using MySQL or the system has full group by turned on.
Here is another approach that will work in any database:
select c.*, e.cnt
from [Contract] c inner join
(select e.ContractId, count(*) as cnt
from Envelope e
group by e.ContractId
having count(*) >= 10
) e
on e.ContractID = c.ID;
This moves the aggregation to a subquery, before the join. You can then take all the columns from the contract table.
You are pretty close. You must include all fileds in the selectt either an aggregate function or the GROUP BY clause. Try this:
select c.id, c.PresenterUserID, COUNT(e.ID)
from [Contract] c
INNER JOIN Envelope e ON e.ContractID = c.ID
Group By c.ID, c.PresenterUserID
HAVING Count(e.ID) >= 10