Using Count and Max in SQL Query - mysql

I have two tables that I am trying to query from, Enrollment and Course. In the course Table, there is just one entry for each course, but in the Enrollment table, there is an entry for each student that is enrolled in any course, so there may be 30 entries for one course. My task is to find The course that has the most enrollments, and print out that course name, as well as the number of enrollments for that course. Here is my query so far
select c.CourseCode ,(SELECT count( * ) FROM Enrollment WHERE CourseCode = c.CourseCode) as test from Course c ;
this gives me the results:
CS227 - 29
CS228 - 34
CS309 - 31
CS311 - 25
, ect, which is good, but NOW, how do I print out only the class that has the most enrollments(in this case, CS228). I have tried using the max(), but I can't get anything to work.
Here is the table structure
create table Course(
CourseCode char(50),
CourseName char(50),
PreReq char (6));
create table Enrollment (
CourseCode char(6) NOT NULL,
SectionNo int NOT NULL,
StudentID char(9) NOT NULL references Student,
Grade char(4) NOT NULL,
primary key (CourseCode,StudentID),
foreign key (CourseCode, SectionNo) references Offering);

Just take the top 1 after ordering by the count.
That is:
Select Top 1 A.CourseCode, Count(*) From Course A inner join Enrollment B on (A.CourseCode=B.CourseCode)
Group By A.CourseCode
Order By Count(*) DESC
Also - use an inner join as I've shown here rather than a subquery. I do tend to like SubQueries and this one will work but it is just not appropriate in this kind of query!

Based on your comment, I think the blow query is what you want, although it is untested and I am not entirely sure on the HAVING clause being valid. From the documentation on MySQL's page, it seems it should work.
SELECT A.CourseCode, COUNT(*) AS count FROM Course A
JOIN Enrollment B ON A.CourseCode = B.CourseCode
GROUP BY A.CourseCode
HAVING count = MAX(count)
As for performance, I cannot tell if it's a good idea to run a MAX on an aggregate function (probably not).
Otherwise, just use the other query to return the top X and simply run through comparing to the previous number.

SELECT
c.CourseCode,
c.CourseName,
COUNT(*) AS cnt
FROM
Course AS c
INNER JOIN
Enrollment AS e
ON c.CourseCode = e.CourseCode
GROUP BY
c.CourseCode
HAVING
COUNT(*) =
( SELECT
COUNT(*) AS cnt
FROM
Enrollment AS e
GROUP BY
e.CourseCode
ORDER BY
cnt DESC
LIMIT 1
)

Related

Complex query on SQL database to get winner of election

I have a few tables that are set up like so:
Table past_elections:
election_ID bigint(15) unsigned;
Date date;
Race varchar(32)
Table candidates:
Candidate_ID bigint(15) unsigned;
FirstName varchar(60);
LastName varchar(60)
Table past_elections-candidates:
PastElection bigint(15);
Candidate bigint(15);
Votes int(8) unsigned
The past_elections-candidates is an intermediate table which links the Primary keys for the Candidate_ID in the candidates table with the election_ID in the past_elections table and I set it up this way because technically a candidate can be in the candidate table and run for more than one race on the same election (Think partial term limits or special elections where they also want to retain their seat for the following term) or where they run for reelection in another year. That is why I made that one-to-many relationship.
My question is, how do I make a query on the database to find all the winners of their races? What about a query to find out which people won their elections with less than X percentage of total votes? I know I'll probably have to use an aggregate function like MAX() along with an INNER JOIN and a GROUP BY but this one seems complex. I'm hoping someone has done something the same or similar before. Although I'm probably going to be told I set up my tables in the most inefficient manner possible for such a query. (Crossing my fingers.)
To get the winner for any event, you need to find the maximum votes per election and then join that back to the past_elections-candidates table to find the candidate number, then join to the candidates table to get their details:
SELECT pe.election_ID as elec,
c.FirstName,
c.LastName,
pecs.max_votes AS votes,
pecs.max_votes / pecs.total_votes AS percent
FROM past_elections pe
JOIN `past_elections-candidates` pec ON pec.PastElection = pe.election_ID
JOIN (SELECT PastElection,
MAX(Votes) AS max_votes,
SUM(Votes) AS total_votes
FROM `past_elections-candidates`
GROUP BY PastElection) pecs ON pecs.PastElection = pec.PastElection AND pecs.max_votes = pec.votes
JOIN candidates c ON c.Candidate_ID = pec.Candidate
Output:
elec FirstName LastName votes percent
1 Aladdin Arabia 200 0.5714
2 Robin Hood 150 0.4286
Demo on dbfiddle

How do I write an SQL query that gives me the amount of times a value is repeated in a table?

So I have two tables which I have created:
CREATE TABLE IF NOT EXISTS `Advertising_Campaign` (
`CampaignID` VARCHAR(10) NOT NULL,
`AdvertName` varchar(45) NOT NULL,
`ProjectLead` VARCHAR(10) NULL,
`CostEstimate` decimal NULL,
`CampaignCost` decimal NULL,
`EndDateEst` date NULL,
`StartDate` date NULL,
`EndDate` date NULL,
`Theme` VARCHAR(45) NOT NULL,
`AdvertType` VARCHAR(45) NOT NULL,
PRIMARY KEY (`CampaignID`))
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `staff_works_campaign` (
`CampaignID` VARCHAR(10) NOT NULL,
`StaffID` VARCHAR(10) NOT NULL,
`SalaryGrade` Integer NOT NULL,
`isSup` VARCHAR(3) NOT NULL,
PRIMARY KEY (`StaffID`, `CampaignID`),
CONSTRAINT `FK_StaffID3` FOREIGN KEY (`StaffID`) REFERENCES `Staff` (`StaffID`),
CONSTRAINT `FK_CampaignID2` FOREIGN KEY (`CampaignID`) REFERENCES `Advertising_Campaign` (`CampaignID`))
ENGINE = InnoDB;
which gives the tables:
Basically, I want to write a query that will return me a list of the advertising_campaign.AdvertName with more than 2 staff members working on them and a count of the number of staff members whose staff_works_campaign.SalaryGrade is greater than 2.
I have tried:
select a.advertname, count(*) as 'Greater Than 2'
from advertising_campaign a inner join staff_works_campaign
where staff_works_campaign.SalaryGrade > 2;
Which isn't exactly what I want, it returns:
I am a bit unsure at what this is returning exactly because I would thought it would have returned a count of 2(because of the fact that there are 2 entries with a SalaryGrade of 4 in the table), might be because of the way inner join works?
I am also a bit confused as to how to filter for 'more than 2 staff members', My idea is to see the amount of times the staff_works_campaign.CampaignID has appeared in the staff_works_campaign table to see how many staff members are apart of the same campaign.
I'm not sure how to structure it to count the amount of times campaignID is repeated and to return the names of the adverts that have a campaignID that has 2 or more staff members working on it.
So in this case I would want it to return a table with AdvertName of only those campaigns with two or more people working on them and a count of those staff members who have a salary grade greater than 2.
SELECT
a.CampaignID
,a.AdvertName
,COUNT(DISTINCT s.StaffID) AS [Count of staff]
,SUM(
--Use this to get a total of the staff who are
--in a SalaryGrade greater than 2
CASE WHEN s.SalaryGrade > 2
THEN 1
ELSE 0 --anyone who is under this level will be a 0 and not count
END
) as [Count of staff above salary grade]
FROM
advertising_campaign AS a
INNER JOIN staff_works_campaign AS s
--dont forget the join condition
ON a.CampaignID = s.CampaignID
--Dont want a where here, we want to include ALL staff.
--WHERE
-- staff_works_campaign.SalaryGrade > 2
GROUP BY
a.CampaignID
,a.AdvertName
HAVING
--more than two members of staff working on the same campaign.
COUNT(DISTINCT s.StaffID) > 2
Firstly you need a condition to join the two tables on. Secondly you can use a Group By and Having clause to put the filter on aggregation. Finally you need to count the number of staff with a salary grade > 2, which you can SUM a conditional for. Something like this:
select a.advertname, Sum(CASE WHEN c.SalaryGrade > 2 THEN 1 ELSE 0 END) as 'Greater Than 2'
from advertising_campaign a inner join staff_works_campaign c
on a.CampaignId = c.CampaignId
Group By a.advertname Having count(*) >= 2;
You can do something like following if you want both conditions together,
2 people working on camp, whose salary_grade >2
SELECT AdvertName
FROM Advertising_Campaign
WHERE CampaignID IN
(
SELECT
CampaignID
FROM
staff_works_campaign
WHERE
SalaryGrade > 2
GROUP BY
CampaignID
HAVING
COUNT(DISTINCT StaffID) >= 2
)
What you have received as a result from your query is the count of all staff members across all campaigns that have a salary grade greater than 2. It returns "Star Wars 3" as the advert name simply because it's the first name it came across in all the results that the COUNT operates over. (Some other SQL technologies such as Microsoft SQL Server actually won't allow you to do this kind of query to avoid this confusion.)
In order to get the results to be split by the campaign, you have to use the GROUP BY clause as suggested in the other answers. This will tell SQL to calculate any aggregate functions (i.e. COUNT) over groups of records that all match for one or more fields. In your case, you want to group by the campaignID, since you want the COUNT to be calculated for each campaign individually. You could do this on the advert name as well, but better to do it on the ID in case you have two with the same name. Modifying your query to do that, we get:
select a.campaignID, count(*) as 'Greater Than 2'
from advertising_campaign a inner join staff_works_campaign
where staff_works_campaign.SalaryGrade > 2
group by a.campaignID;
This still isn't quite going to work though, because the salary grade condition is applied before the COUNT. We need to move that part out into a new query that wraps around this one. We also need to limit the campaigns down to those with two staff - thankfully, we don't need yet another outer query for that. The HAVING keyword allows a condition to be applied after a GROUP BY, so we can do:
select a.campaignID, count(*) as 'staff_amount'
from advertising_campaign a inner join staff_works_campaign
group by a.campaignID
having staff_amount > 2;
Now, adding the staff salary condition and another select from advertising_campaign to get the advert name in an outer query, we finally get:
select advertising_campaign.advertname
from advertising_campaign
inner join staff_works_campaign on advertising_campaign.campaignid = staff_works_campaign.campaignid
inner join
(
select a.campaignID, count(*) as 'staff_amount'
from advertising_campaign a inner join staff_works_campaign
group by a.campaignID
having staff_amount > 2
) large_campaigns on advertising_campaign.campaignid = large_campaigns.campaignid
where staff_works_campaign.salarygrade > 2

how does the count function in mysql work?

First and foremost, this is part of an assignment, but I'm trying to get more clarification on how the count() function works when querying a db.
The question is: List the name, SSN and the number of courses the student has taken (courses with the same CourseNumber taken in different quarters are counted as different courses).
I've been querying using this:
SELECT S.Name, S.SSN, COUNT(*)
FROM Student S, Enrollment E
WHERE S.SSN = E.SSN
GROUP BY S.SSN
which seems to return the correct answer, but I'm not sure why. As a result, I can't seem to get the next questions (assuming courses with the same CourseNumber taken in different quarters are considered as one course) correct.
Here are the create table commands so you can see which table holds what info:
CREATE TABLE Student(
SSN INT(9),
Name VARCHAR(20),
Major VARCHAR(30),
PRIMARY KEY (SSN)
);
CREATE TABLE Course(
CourseNumber INT(5),
PrerequisiteCourseNumber INT(10),
CourseTitle VARCHAR(10),
NumberUnits INT(2),
PRIMARY KEY (CourseNumber)
);
CREATE TABLE Section(
CourseNumber INT(5),
Quarter VARCHAR(10),
RoomNumber INT(5),
DayTime VARCHAR(20),
PRIMARY KEY (CourseNumber,Quarter),
FOREIGN KEY (CourseNumber) REFERENCES Course(CourseNumber)
);
CREATE TABLE Enrollment(
SSN INT(9),
CourseNumber INT(5),
Quarter VARCHAR(10),
Grade VARCHAR(1),
PRIMARY KEY (SSN,CourseNumber,Quarter),
FOREIGN KEY (SSN) REFERENCES Student(SSN),
FOREIGN KEY (CourseNumber) REFERENCES Course(CourseNumber),
FOREIGN KEY (Quarter) REFERENCES Section(Quarter)
);
Any pointers?
what you are doing is using old join syntax (pre ansi syntax) where you do a cross join of tables and use the where to turn it into a join. an equivalent query would be this.
SELECT S.Name, S.SSN, COUNT(*)
FROM Student S
JOIN Enrollment E ON S.SSN = E.SSN
GROUP BY S.SSN
Now to answer your question about what the count is doing and stuff..
COUNT() returns a count of every row that is returned.
GROUP BY groups all of the records by a common ground aka your SSN field. so if a student has 5 SSN rows in the table then his count will be 5.
Now for the part you are looking for with course numbers.. you need to JOIN those tables on appropriate fields and add a field to your group by for each quarter
aka add to the previous code..
WHERE E.quarter = whatever_quarter_you_want
you can add more to this query if you need to. but add data to your question if you want a more full answer.
Your current query is:-
SELECT S.Name, S.SSN, COUNT(*)
FROM Student S
INNER JOIN Enrollment E
ON S.SSN = E.SSN
GROUP BY S.SSN
What this is doing is joining student to enrollment, so giving multiple rows for each student, one for each course / quarter they are enrolled on. It is then grouped by SSN (student number?) to count up the number of course / quarters they are enrolled on. You should really group by S.Name as well (while MySQL won't object, most flavours of SQL would).
Note that COUNT(*) counts the number of rows. You could use COUNT(E.CourseNumber) which would count the number of rows where course number is not null. Not really useful here, but can be useful with LEFT OUTER JOINs. You can also use COUNT(DISTINCT CourseNumber) to count the number of unique non null course numbers for the student.
A LEFT OUTER JOIN might also be better as this would enable you to return 0 as the counts for students who exist but who are not enrolled in any courses:-
SELECT S.Name, S.SSN, COUNT(DISTINCT E.CourseNumber)
FROM Student S
LEFT OUTER JOIN Enrollment E
ON S.SSN = E.SSN
GROUP BY S.Name, S.SSN
SELECT S.Name, S.SSN, COUNT(*)
FROM Student S, Enrollment E, Section Sec, Course C
WHERE S.SSN = E.SSN AND E.CourseNumber = Sec.CourseNumber
AND Sec.CourseNumber = C.CourseNumber AND Sec.Quarter like E.Quarter
GROUP BY S.Name, S.SSN

How can I write a query that shows the Institutions that have more than one one contact at them?

CREATE TABLE Institutions
(
Institution_ID INTEGER PRIMARY KEY,
Institution_Name VARCHAR(200))
CREATE TABLE Contact_Persons
(
Contact_No INTEGER PRIMARY KEY,
First_Name VARCHAR(60) NOT NULL,
Last_Name VARCHAR(60) NOT NULL,
Institution_ID INTEGER,
FOREIGN KEY (Institution_ID) REFERENCES Institutions(Institution_ID))
How can I write a mysql query that shows the Institutions that have more than one one Contact Person at them? The Query should show Institution_ID and Institution_Name from Table Institutions. The following Query works but It only shows Institution_ID. I want to see Institution_Name too. I think there must be a join between these two tables. Please help.
SELECT Institution_ID
FROM Contact_Persons
GROUP BY Institution_ID
HAVING COUNT(*)>1;
You were right, you just need to join your two tables, and make sure you also group by everything you want to select (unless it is an aggregate), so in this case add Institution_Name to the group by clause:
SELECT i.Institution_ID, i.Institution_Name
FROM Contact_Persons AS cp
INNER JOIN Institutions AS i
ON i.Institution_ID = cp.Institution_ID
GROUP BY i.Institution_ID, i.Institution_Name
HAVING COUNT(*) > 1;
Try this
SELECT I.Institution_ID,I.Institution_name
FROM Contact_Persons as C inner join Institutions as I on
C.Institution_ID=I.Institution_ID
GROUP BY I.Institution_ID,I.Institution_name
HAVING COUNT(*)>1;

SQL statement that shows at least 16 courses not taken

I have four schemas:
takes(ID,course_id,sec_id,semester,year)
student(ID,name,dept_name,tot_credit)
course(course_id,title,dept_name,credits)
department(dept_name,building,budget)
I want to create a query that finds the name and id of each Astronomy student whose name begins with the letter ’T’ and who has not taken at least 16 Astronomy courses.
What's the easiest way I could do this?
I already wrote this beginning bit
SELECT name, id
FROM student
WHERE dept_name='Astronomy' AND name LIKE '%T%'
I'm not quite sure how to finish this off.
Any help would be greatly appreciated :)
Here's the result
NAME ID CLASS_TAKEN
-------------------- ----- -----------
Tolle 38279 12
Teo 62268 13
Tolle 93223 13
Tsukamoto 17707 5
Titi 11576 9
Teo 91772 12
Toraichi 50387 11
Tewari 80754 14
Tiroz 64091 14
9 rows selected
I need Teo with the id 91772 and Tewari 80754 to be gone
Given my reading of the requirements and the comments it's pretty clear that the question is not very clear. :-) What you're looking for are students where (total # of courses given by the Astronomy department) - (# of Astronomy courses taken by student) >= 16. So, how do we find these values? First, let's start with the total number of courses given by the Astronomy department. This is pretty simple:
SELECT COUNT(*) AS ASTRONOMY_COURSE_COUNT
FROM COURSE
WHERE DEPT_NAME = 'ASTRONOMY'
Now, the second part is to determine how many courses given by the Astronomy department each student has taken. To do this we need to start with the student, join to the courses the student has taken (the TAKES table), then join to the COURSES table to find out which department each course is part of. Something like the following should do it:
SELECT s.ID, s.NAME, COUNT(*) AS STUDENT_ASTRO_COUNT
FROM STUDENT s
INNER JOIN TAKES t
ON t.ID = s.ID
INNER JOIN COURSE c
ON c.COURSE_ID = t.COURSE_ID
WHERE c.DEPT_NAME = 'ASTRONOMY' AND
s.NAME LIKE 'T%'
GROUP BY s.ID, s.NAME;
OK, now we need to put this together. You've tagged this question for both Oracle and MySQL so I'm going to guess you'll accept valid syntax for either database; thus I'll use Oracle Common Table Expression syntax to pull everything together:
WITH ASTRONOMY_COURSES AS (SELECT COUNT(*) AS ASTRONOMY_COURSE_COUNT
FROM COURSE
WHERE DEPT_NAME = 'ASTRONOMY'),
STUDENT_ASTRO_COURSES AS (SELECT s.ID,
s.NAME,
COUNT(*) AS STUDENT_ASTRO_COUNT
FROM STUDENT s
INNER JOIN TAKES t
ON t.ID = s.ID
INNER JOIN COURSE c
ON c.COURSE_ID = t.COURSE_ID
WHERE c.DEPT_NAME = 'ASTRONOMY' AND
s.NAME LIKE 'T%'
GROUP BY ID)
SELECT s.ID,
s.NAME,
s.STUDENT_ASTRO_COUNT,
a.ASTRONOMY_COURSE_COUNT - s.STUDENT_ASTRO_COUNT AS UNTAKEN_COUNT
FROM STUDENT_ASTRO_COURSES s
CROSS JOIN ASTRONOMY_COURSES a
WHERE a.ASTRONOMY_COURSE_COUNT - s.STUDENT_ASTRO_COUNT >= 16;
Note here that a CROSS JOIN is used to put together the subqueries. This means that all the rows of each subquery are joined to all the rows of the other subquery - but since in this case the ASTRONOMY_COURSES subquery will only return a single row what we're doing is appending the ASTRONOMY_COURSE_COUNT value onto each row returned by the STUDENT_ASTRO_COURSES subquery.
That should at least get you pretty close. Amend as needed.
Not tested on animals - you'll be first! :-)
Share and enjoy.
Do you need to use all tables?
Table department has no links with the student,
Table takes has no links with the student,
Table coursehas no links with the student.
If student lists total credits that are all Astronomy I think this can be used:
select name, id, MAX(tot_credit) as credits
from student
where dept_name='Astronomy' and name like 'T%'
group by name, id
having MAX(tot_credit)<=16
PS - you schema is not good; PK-FK references are missing
Your query will need to reference more tables than just the student table.
Your tables seem be missing some important information, which student has taken which course. There's a table named takes, but there doesn't appear to be any relationship between takes and student.
So first, figure out how to list the students along with the Astronomy courses they have taken. Each row will identify the student and a course.
SELECT s.id AS student_id
, s.name AS student_name
, t.???
FROM student s
JOIN ??? t
ON t.student_id = s.id
WHERE ...
You may also need to include another "join" to an additional table, in order to identify which course a student has taken is an Astronomy course.
To also include students that have not take any Astronomy courses, you can use an outer join, rather than an inner join. (That would mean including the LEFT keyword before JOIN, and relocating predicates from the WHERE clause to the ON clause. (A predicate in the WHERE clause that can only be satisfied by non-NULL values will negate the outer-ness of the join.)
Once you have a query that returns that set (students along with any astronomy courses they've taken), you can then add a GROUP BY clause to "collapse" a set of rows into a single row. (Looks like you want the rows "grouped" by student.)
And then an aggregate function like COUNT() or SUM() can be used to get a count of rows for each group. (If you don't want to count any re-takes of a course (a "duplicate" course for a student) you may be able to make use of the COUNT(DISTINCT t.foo) form.
And then a HAVING clause can be added to the query, to compare the value returned from the aggregate expression to a constant value, to return only rows that satisfy a specific condition.
FOLLOWUP
Assuming:
CREATE TABLE course
( id INT UNSIGNED NOT NULL COMMENT 'PK'
, title VARCHAR(30) NOT NULL COMMENT 'course title'
, dept_name VARCHAR(30) NOT NULL COMMENT 'FK ref dept.name'
, credits DECIMAL(5,2) COMMENT 'credit hours'
, PRIMARY KEY (id)
);
CREATE TABLE student
( id INT UNSIGNED NOT NULL COMMENT 'PK'
, name VARCHAR(30) NOT NULL COMMENT 'student name'
, dept_name VARCHAR(30) NOT NULL COMMENT 'FK ref dept.name'
, tot_credit INT COMMENT '?'
, PRIMARY KEY (id)
);
CREATE TABLE takes
( student_id INT UNSIGNED NOT NULL COMMENT 'FK ref student.id'
, course_id INT UNSIGNED NOT NULL COMMENT 'FK ref course.id'
, sec_id INT UNSIGNED NOT NULL COMMENT '?'
, semester INT UNSIGNED NOT NULL COMMENT '?'
, year INT UNSIGNED NOT NULL COMMENT '?'
, PRIMARY KEY (student_id, course_id, sec_id, semester, year)
, CONSTRAINT FK_takes_course FOREIGN KEY (course_id) REFERENCES course (id)
, CONSTRAINT FK_takes_student FOREIGN KEY (student_id) REFERENCES student (id)
);
Query to get a list of students...
SELECT s.id
, s.name
FROM student s
WHERE s.name LIKE 'T%'
AND s.dept_name = 'ASTRONOMY'
Get list of students along with the courses they've taken, returning the id of the ASTRONOMY courses they've taken...
SELECT s.id AS student_id
, s.name AS student_name
, c.id AS course_id
FROM student s
LEFT
JOIN takes t
ON t.student_id = t.id
LEFT
JOIN course c
ON c.id = t.course_id
AND c.dept_name = 'ASTRONOMY'
WHERE s.name LIKE 'T%'
AND s.dept_name = 'ASTRONOMY'
Collapse the rows to one per student using a GROUP BY, and use aggregate functions to get counts or totals.
SELECT s.id AS student_id
, s.name AS student_name
, SUM(c.credits) AS total_astronomy_credits_taken
, COUNT(c.id) AS count_astronomy_courses_taken
, COUNT(DISTINCT c.id) AS count_distinct_astronomy_courses_taken
FROM student s
LEFT
JOIN takes t
ON t.student_id = t.id
LEFT
JOIN course c
ON c.id = t.course_id
AND c.dept_name = 'ASTRONOMY'
WHERE s.name LIKE 'T%'
AND s.dept_name = 'ASTRONOMY'
GROUP
BY s.id
, s.name
To omit rows from this resultset, add a HAVING clause. For example, to exclude rows where total_astronomy_credits_taken is greater than or equal to 12...
HAVING total_astronomy_credits_taken >= 12
If you want the rows returned in a certain sequence, specify that in an ORDER BY clause
ORDER BY s.id
If you want to replace NULL values from the aggregates with zeroes, you can warp the aggregate expression in an IFNULL(foo,0) function, e.g.
, IFNULL(COUNT(c.id),0) AS count_astronomy_courses_taken
Try this :
select a.name, a.id, count(b.ID) as class_taken
from student a inner join takes b
on a.ID = b.ID
inner join course c
on b.course_id = c.course_id
where a.dept_name='Astronomy' and substring(a.name,1,1) = 'T'
group by a.name, a.id
having count(b.ID) < 17