I have the following relation in database
ENROLLMENT (snum: int, cname:varchar(100))
where snum is the student id and cname is the course name
and I want to find the name(s) of the class(s) with the most students enrolled.
There are multiple solutions. One solution is usage of SELECT TOP 1 :
SELECT TOP 1
cname, count(*) as NumberOfStudents
FROM ENROLLMENT
GROUP BY cname
ORDER BY count(*) desc
Use a common table expression (cte):
with cte as
(
select cname, count(*) as cnt
from ENROLLMENT
group by cname
)
select cname
from cte
where cnt = (select max(cnt) from cte)
Related
I am trying to find in my database records which has duplicated fields like name, surname and type.
Example:
SELECT name, surname, type, COUNT(*)
FROM customers
GROUP BY name, surname
HAVING COUNT(*)>1
Query results:
Robb|Stark|1|2
Tyrion|Lannister|1|3
So we have duplicated customer with name and surname "Robb Stark" 2 times and "Tyrion Lannister" 3 times
Now, I want to know the id of these records.
I found similar problem described here:
Finding duplicate values in a SQL table
there is answer but no example.
Use COUNT as an analytic function:
WITH cte AS (
SELECT *, COUNT(*) OVER (PARTITION BY name, surname) cnt
FROM customers
)
SELECT * -- return all columns
FROM cte
WHERE cnt > 1
ORDER BY name, surname;
The simplest way will be to use the EXISTS as follows:
SELECT t.*
FROM customers t
where exists
(select 1 from customers tt
where tt.name = t.name
and tt.surname = t.surname
and tt.id <> t.id)
Or use your original query in IN clause as follows:
select * from customers where (name, surname) in
(SELECT name, surname
FROM customers
GROUP BY name, surname
HAVING COUNT(*)>1)
If you want one row per group of duplicate, with the list of id in a comma separated string, you can just use string aggration with your existing query:
SELECT name, surname, COUNT(*) as cnt,
STRING_AGG(id, ',') WITHIN GROUP (ORDER BY id) as all_ids
FROM customers
GROUP BY name, surname
HAVING COUNT(*) > 1
Suppose we have the table students (name, grade, group, year)
We want a query that ranks for each group the corresponding students.
I know that this can be done easy with rank() OVER ( partition by group order by grade DESC ). But I think that this can also be done with a self join or a subquery. Any ideas?
The equivalent to rank() is:
select s.*,
(select 1 + count(*)
from students s2
where s2.group = s.group and
s2.grade > s.grade
) as rank
from students s;
Hi I have a schema that look like this
I made two queries that had to do this:
Find the names of the top 4 instructors who have taught the most number of distinct courses. Display also the total number of courses taught.
Output columns: InstructorName, NumberOfCoursesTaught
Sort by: NumberOfCoursesTaught in descending order
Find the top 2 students who have taken the most number of courses.
Output columns: S_ID, StudentName, NumberOfCourses
Sort by: NumberOfCourses in descending order
For query 1, I wrote:
SELECT name AS InstructorName, count(course_id) AS NumberOfCourses
FROM Teaches
WHERE name IN (SELECT name FROM Instructor where Instructor.i_id = Teaches.i_id)
GROUP BU i_id
ORDER BY COUNT(course_id) DESC;
For query 2, I wrote
SELECT s_id as S_ID, name as StudentName, count(course_id) as NumberOfCourses
FROM Takes
WHERE name IN (SELECT name FROM Student WHERE Takes.s_id = Student.s_id)
GROUP BY s_id
ORDER BY COUNT(course_id) DESC;
Both say:
"NAME" Invalid identifier
I suggest that you should use another logic to build your queries. Here is a demonstration for the first query ; from there on, you should be able to create the second query (and maybe post it as an answer?).
Start with an aggregate query that computes the number of teaches per instructor id, looking at the Teaches table:
SELECT i_id, COUNT(*) cnt FROM Teaches GROUP BY i_id
Then rank each record by decreasing count, using window function ROW_NUMBER() :
SELECT i_id, cnt, ROW_NUMBER() OVER(ORDER BY cnt DESC) rn
FROM (SELECT i_id, COUNT(*) cnt FROM Teaches GROUP BY i_id) t
All that is left to do is get thte instructor name (JOIN ON Instructor) and filter in the top 4 records
SELECT i.name InstructorName, x.cnt NumberOfCoursesTaught
FROM (
SELECT i_id, cnt, ROW_NUMBER() OVER(ORDER BY cnt DESC) rn
FROM (SELECT i_id, COUNT(*) cnt FROM Teaches GROUP BY i_id) t
) x
INNER JOIN Instructor i ON i.i_id = x.i_id
WHERE x.rn <= 4
ORDER BY x.cnt desc
I have this table Student :
Id (int , primary key identity)
Name (varchar(20))
Score (int)
RecordDate (DateTime)
I need to select all the columns of this table plus an extra column that represents the 'Sum' of 'Score' column depending of the Name of the student.
I tried this but it didn't work
select S.Id,S.Name ,S.Score ,S.RecordDate, ( select Sum(Score) from Student where Name= S.Name) as All_Student_Score
from Student S;
How can I change this query ?
You can use a `JOIN`:
SELECT S.*,
T.All_Student_Score
FROM Student S
INNER JOIN (SELECT Name, SUM(Score) All_Student_Score
FROM Student) T
ON S.Name = T.Name;
You can try like this
select Id,Name ,Score ,RecordDate, sum(score) over(partition by name) as All_Student_Score from Student S
The below solution works for your requirement.
select Id,
Name,
Score,
RecordDate,
sum(score) over( partition by name ) as All_Student_Score
from Student;
Because no one showed you that your own solution should work if you just alias your table in your sub query you can do the following:
select
S.Id,S.Name
,S.Score
,S.RecordDate
,(select Sum(Score) from Student s2 where s2.Name= S.Name) as All_Student_Score
from
Student S;
so i have 3 tables linked together named office, employee, and dependent.
office: Oid (PK), officeName
employee: EID(PK), Fname, Lname, JobTitle, Salary, DOH, Gender, DOB, OID(FK1), Supervisor(FK2)
Dependent: DID(PK), Fname, Lname, Gender, EID(FK1)
Here is the link to the picture of the tables:
http://classweb2.mccombs.utexas.edu/mis325/class/hw/hw12a.jpg
I need to display concatenated name and EID of 5 employees with the largest number of dependents, if there is a tie for the five largest, then I need to display all of the tying employees.
I am confused on how to begin. please help :)
thank you in advance
Just break down the problem:
How many dependents an EID has:
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
Add a rank
SELECT EID, C, RANK() OVER (ORDER BY C DESC)
FROM (
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
) S
We want the first 5
SELECT EID
FROM (
SELECT EID, C, RANK() OVER (ORDER BY C DESC) AS R
FROM (
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
) S
) S2
WHERE R <= 5
Now ask for what you want:
SELECT * -- or whatever
FROM Employee
WHERE EID IN (
SELECT EID
FROM (
SELECT EID, C, RANK() OVER (ORDER BY C DESC) AS R
FROM (
SELECT EID, COUNT(*) AS C
FROM Dependent
GROUP BY EID
) S
) S2
WHERE R <=5
) S3
I suggest you run each step and make sure it gives you the expected results.
Ummm I would try something like this:
Select TOP 5
a.FNAME,
a.LNAME,
a.EID,
Count(b.EID) as Dependents
FROM employee a
LEFT JOIN dependent b on a.EID = b.EID
group by 1,2,3 order by Dependents desc