Name of Teacher with Highest Wage - recursive CTE - sql

I am trying to get the max salary of each dept and display that teacher by first name as a separate column. So dept 1 may have 4 rows but one name showing for max salary. I'm Using SQL SERVER
With TeacherList AS(
Select Teachers.FirstName,Teachers.LastName,
Teachers.FacultyID,TeacherID, 1 AS LVL,PrincipalTeacherID AS ManagerID
FROM dbo.Teachers
WHERE PrincipalTeacherID IS NULL
UNION ALL
Select Teachers.FirstName,Teachers.LastName,
Teachers.FacultyID,Teachers.TeacherID, TeacherList.LVL +
1,Teachers.PrincipalTeacherID
FROM dbo.Teachers
INNER JOIN TeacherList ON Teachers.PrincipalTeacherID =
TeacherList.TeacherID
WHERE Teachers.PrincipalTeacherID IS NOT NULL)
SELECT * FROM TeacherList;
SAMPLE OUTPUT :
Teacher First Name | Teacher Last Name | Faculty| Highest Paid In Faculty
Eric Smith 1 Eric
Alex John 1 Eric
Jessica Sewel 1 Eric
Aaron Gaye 2 Aaron
Bob Turf 2 Aaron

I'm not sure from your description but this will return all teachers and the last row is the name of the teacher with the highest pay on the faculty.
select tr.FirstName,
tr.LastName,
tr.FacultyID,
th.FirstName
from Teachers tr
join (
select FacultyID, max(pay) highest_pay
from Teachers
group by FacultyID
) t on tr.FacultyID = t.FacultyID
join Teachers th on th.FacultyID = t.FacultyID and
th.pay = t.highest_pay
this will produce an unexpected result (duplicate rows) if there are more persons with the highest salary on the faculty. In such case you may use window functions as follows:
select tr.FirstName,
tr.LastName,
tr.FacultyID,
t.FirstName
from Teachers tr
join
(
select t.FirstName,
t.FacultyID
from
(
select t.*,
row_number() over (partition by FacultyID order by pay desc) rn
from Teachers t
) t
where t.rn = 1
) t on tr.FacultyID = t.FacultyID
This will display just one random teacher from faculty with highest salary.
dbfiddle demo

You can do this with a CROSS APPLY.
SELECT FirstName, LastName, FacultyID, HighestPaid
FROM Teachers t
CROSS APPLY (SELECT TOP 1 FirstName AS HighestPaid
FROM Teachers
WHERE FacultyID = t.FacultyID
ORDER BY Salary DESC) ca

Related

Find students who take most courses SQL

Assume there's a table students containing student id, semester id and number of courses taken in each semester:
student semester num_courses
10001 23 3
10002 23 5
10003 23 1
10004 25 2
10005 25 3
10003 25 5
10000 26 4
10013 26 2
...
How can I find students in each semester who took the largest number of courses?
Expected output would be:
student semester num_courses
10002 23 5
10003 25 5
10000 26 4
...
I thought of using OVER PARTITION BY, but I'm not sure how to use it correctly with this type of query. What I got is not working as expected.
SELECT s.student, s.semester, MAX(s.num_courses) OVER (PARTITION BY s.semester) AS max
FROM students s;
Your idea is good. Now that you have the students' semester course counts along with the maximum semester course counts, compare the two:
SELECT semester, num_courses, student
FROM
(
SELECT
student,
semester,
num_courses,
MAX(num_courses) OVER (PARTITION BY semester) AS semester_max_num_courses
FROM students s
) with_max
WHERE num_courses = semester_max_num_courses
ORDER BY semester, student;
Another approach would be to select all maximum semester course counts and then use this to get the students:
SELECT semester, num_courses, student
FROM students
WHERE (semester, num_courses) IN
(
SELECT semester, MAX(num_courses)
from students
GROUP BY semester
)
ORDER BY semester, student;
With row_number() you can easily have a serial number in descending order of num_courses. Then just pick the rows with first serial number for each semister.
Subquery:
select student ,semester, num_courses from
(
Select student ,semester, num_courses, row_number()over(partition by semester
order by num_courses desc)rn from students
)t
where rn=1
Common table expression
With cte as
(
Select student ,semester, num_courses, row_number()over(partition by semester
order by num_courses desc)rn from students
)
select student ,semester, num_courses from cte where rn=1
Another approach, also if more than one student has max number of courses
WITH cte as
(
SELECT s.semester, MAX(s.num_courses) as num
FROM students s
GROUP BY s.semester
)
SELECT s.student, s.semester, s.num_courses FROM students s JOIN cte on s.semester =
cte.semester
WHERE cte.num = s.course
ORDER BY s.semester
If you want one row per semester, then in Postgres, I would recommend distinct on:
select distinct on (semester) s.*
from students s
order by semester, num_courses desc;
If you want all students who have the maximum number, then Thorsten's answer is appropriate.

SQL Server : finding duplicates based on first few characters on column

I want to find duplicates based on the first three characters of the surname, is there a way a to do that on SQL? I can compare the whole name, but how to do we compare the first few characters?
Below are my tables
custid forename surname dateofbirth
----------------------------------------
1 David John 16-09-1985
2 David Jon 16-09-1985
3 Sarah Smith 10-08-2015
4 Peter Proca 11-06-2011
5 Peter Proka 11-06-2011
This is my query that I am currently running to compare
SELECT
y.id, y.forename, y.surname
FROM
customers y
INNER JOIN
(SELECT
forename, surname, COUNT(*) AS CountOf
FROM customers
GROUP BY forename, surname
HAVING COUNT(*) > 1) dt ON y.forename = dt.forename
You can use left():
select c.*
from (select c.*, count(*) over (partition by left(surname, 3)) as cnt
from customers c
) c
order by surname;
You can include the forename as well in the partition by if you mean forename and first three letters of surname.
You can use exists as follows:
select t.* from t
Where exists
(select 1 from t tt
Where left(t.surname, 3) = left(tt.surname, 3) and t.custid <> tt.custid
)
order by t.surname;

Highest salary per department (also same salary)

How can I select the highest salary on each department with a same salary.
My query is only to get the first row in each department with the same salary. But I want to select all max same salary on each department. Please help me out of this problem.
Below is the sample table:
PSD Department
----------------------
Yumang's Salary: $500
Paus Salary: $500
QA Department
----------------------
Villanueva: $1000
Calacar: $1000
Here's the code I am trying:
SELECT MAX(inter_department_votes.number_votes)
FROM employee_salary
GROUP BY dept_id
try selecting dept_id as well:
SELECT dept_id,
MAX(inter_department_votes.number_votes)
FROM employee_salary GROUP BY dept_id
Using RANK() function:
RANK provides the same numeric value for ties (for example 1, 1, 2, 4, 5).
SELECT *
FROM (
SELECT dept_id,
PersonName,
Salary,
RANK() OVER(PARTITION dept_id ORDER BY Salary DESC) AS SortBySalary
FROM employee_salary
)
WHERE SortBySalary = 1
Also, see this answer using MAX() function.
your table isn't clear to me. i can't understand why you're creating separate tables for all departments.
assuming you make two different tables, one for employees and one for department. this will make queries simpler for future and efficient database. In that case:
+----------+------------+------+-----+
|EmployeeID|EmployeeName|Salary|DepNo|
+----------+------------+------+-----+
| |
+----------+------------+------+-----+
+-----+-------+
|DepNo|DepName|
+-----+-------+
| |
+-----+-------+
SELECT DepName, EmployeeName, salary
FROM Department d
INNER JOIN Employee e on e.DepNo = d.DepNo
INNER JOIN
(
SELECT DepNo, MAX(salary) sal
FROM Employee
GROUP BY DepNo
) ss ON e.DepNo = ss.DepNo
AND e.salary = ss.sal;

SQL query to fetch details when one of value is missing

Consider a table with entries for students:
cloumn1 key value
-------------------------------
john age 23
john salary 100
John rollno 12
Raj age 24
Raj rollno 10
I want to get result of salary value when queried on salary and student
name.
It is always queried on salary and student. For the second student since salary record itself is not there. I am facing the issue in fetching the records
SELECT
a.id, b.location, c.value
FROM
boys A, school B,details c
WHERE
A.id = B.id
c.id = a.id
c.key = salary
Request every one to throw your solutions
Thanks in advance
SELECT id,
MAX( CASE key WHEN 'salary' THEN value END ) AS salary
FROM details
GROUP BY id
or
SELECT *
FROM details
PIVOT ( MAX( value )
FOR key IN (
'salary' AS salary,
'rollno' AS rollno,
'age' AS age
) );

count columns group by

I hava the sql as below:
select a.dept, a.name
from students a
group by dept, name
order by dept, name
And get the result:
dept name
-----+---------
CS | Aarthi
CS | Hansan
EE | S.F
EE | Nikke2
I want to summary the num of students for each dept as below:
dept name count
-----+-----------+------
CS | Aarthi | 2
CS | Hansan | 2
EE | S.F | 2
EE | Nikke2 | 2
Math | Joel | 1
How shall I to write the sql?
Although it appears you are not showing all the tables, I can only assume there is another table of actual enrollment per student
select a.Dept, count(*) as TotalStudents
from students a
group by a.Dept
If you want the total count of each department associated with every student (which doesn't make sense), you'll probably have to do it like...
select a.Dept, a.Name, b.TotalStudents
from students a,
( select Dept, count(*) TotalStudents
from students
group by Dept ) b
where a.Dept = b.Dept
My interpretation of your "Name" column is the student's name and not that of the actual instructor of the class hence my sub-select / join. Otherwise, like others, just using the COUNT(*) as a third column was all you needed.
select a.dept, a.name,
(SELECT count(*)
FROM students
WHERE dept = a.dept)
from students a
group by dept, name
order by dept, name
This is a somewhat questionable query, since you get duplicate copies of the department counts. It would be cleaner to fetch the student list and the department counts as separate results. Of course, there may be pragmatic reasons to go the other way, so this isn't an absolute rule.
SELECT dept, name, COUNT(name) as CT from students
group by dept, name
order by dept, name
This should do it (I haven't got any environment to test on at the min)
select a.dept, a.name, count(a.*) as NumOfStudents
from students a
group by dept, name order by dept, name
HTH
Or Otherwise write simply
select dept, name, count(name) as nostud from students group by dept, name order by dept, name
This will give the results requested above
select a.dept, a.name, cnt
from student a
join (
select dept, count(1) as cnt
from student
group by dept
) b on b.dept = a.dept