How to find the number of qualified people per job SQL - sql

What I am trying to do is get the number of qualified people per job.
A person is qualified for a job if they have all the skills a job requires.
Tables:
Job(job_code, job_name)
Job_skill(job_code, s_code)
Skills(s_code, skill_name)
Person(per_id, email)
Person_skill(per_id, s_code)
I’ve been stuck on using the minus as such in the following pseudocode:
For each job
From a table of jobs and persons
Where not exits
For each person
Get jobs of each person
Minus
Get the skills of job
Remove appropriate person
But, I feel this logic is incorrect and may be going down the wrong path entirely.
Any help appreciated.

There is need for a loop:
Given this setup:
create table Job(job_code varchar(10), job_name varchar(100));
insert into job values ('dev', 'Developer');
insert into job values ('mgr', 'Manager');
insert into job values ('designer', 'WebDesigner');
create table Job_skill(job_code varchar(10), s_code varchar(10));
insert into job_skill values ('dev', 'sql');
insert into job_skill values ('dev', 'java');
insert into job_skill values ('dev', 'oop');
insert into job_skill values ('mgr', 'ppt');
insert into job_skill values ('mgr', 'outlook');
insert into job_skill values ('designer', 'html');
insert into job_skill values ('designer', 'css');
insert into job_skill values ('designer', 'graphics');
create table Person(per_id integer, name varchar(254));
insert into person values (1, 'Arthur');
insert into person values (2, 'Zaphod');
insert into person values (3, 'Tricia');
insert into person values (4, 'Ford');
create table Person_skill(per_id integer, s_code varchar(10));
insert into person_skill values (1, 'sql');
insert into person_skill values (1, 'java');
insert into person_skill values (1, 'oop');
insert into person_skill values (2, 'ppt');
insert into person_skill values (3, 'html');
insert into person_skill values (3, 'css');
insert into person_skill values (3, 'graphics');
insert into person_skill values (4, 'ppt');
insert into person_skill values (4, 'outlook');
Arthur is qualified as a Developer, Tricia as a WebDesigner and Ford as a Manager. Zaphod can only use outlook so he lacks the PowerPoint skills to be a manager.
The following query shows that for each person:
with skill_count as (
select ps.per_id,
js.job_code,
count(js.s_code) as num_skills
from person_skill ps
join job_skill js on ps.s_code = js.s_code
group by ps.per_id, js.job_code
order by ps.per_id
), required_skills as (
select job_code, count(*) as num_required
from job_skill
group by job_code
)
select p.name,
sc.job_code,
case
when sc.num_skills = rs.num_required then 'qualified'
else 'not qualified'
end as status
from skill_count sc
join required_skills rs on sc.job_code = rs.job_code
join person p on sc.per_id = p.per_id
order by p.name;
The result based on the sample data is:
name | job_code | status
-------+----------+--------------
Arthur | dev | qualified
Ford | mgr | qualified
Tricia | designer | qualified
Zaphod | mgr | not qualified

Related

While combining tables, how to make a column distinct when it has multiple entries?

I'm trying to display course numbers from table student_enrollment and student names from table students, based on a distinct last_name from table professors. For example, there is a professor named "Wilson" - I would like to only display the courses Wilson's teaching and the students that are enrolled in these classes.
What I have so far is the following, which displays the unique course numbers that each student is enrolled in but does not take into consideration of professors.last_name:
SELECT students.student_name, student_enrollment.course_no
FROM students, student_enrollment, teach
WHERE students.student_no=student_enrollment.student_no
AND student_enrollment.course_no=teach.course_no
GROUP BY student_name,student_enrollment.course_no
Please see the four queried tables (students, student_enrollment, teach, professors) below for more information:
create table students
(
student_no integer,
student_name varchar(20),
age integer
);
insert into students values (1, 'Harpreet', 19);
insert into students values (2, 'Doug', 18);
insert into students values (3, 'Abdul', 21);
insert into students values (4, 'Mohammad', 20);
insert into students values (5, 'Ralph', 19);
insert into students values (6, 'Prateek', 22);
insert into students values (7, 'Michael', 19);
insert into students values (8, 'Jack', 19);
insert into students values (9, 'Chin', 17);
insert into students values (10, '', 20);
create table courses
(
course_no varchar(5),
course_title varchar(20),
credits integer
);
insert into courses values ('CS110', 'Pre Calculus', 4);
insert into courses values ('CS180', 'Physics', 4);
insert into courses values ('CS107', 'Intro to Psychology', 3);
insert into courses values ('CS210', 'Art History', 3);
insert into courses values ('CS220', 'US History', 3);
create table student_enrollment
(
student_no integer,
course_no varchar(5)
);
insert into student_enrollment values (1, 'CS110');
insert into student_enrollment values (1, 'CS180');
insert into student_enrollment values (1, 'CS210');
insert into student_enrollment values (2, 'CS107');
insert into student_enrollment values (2, 'CS220');
insert into student_enrollment values (3, 'CS110');
insert into student_enrollment values (3, 'CS180');
insert into student_enrollment values (4, 'CS220');
insert into student_enrollment values (5, 'CS110');
insert into student_enrollment values (5, 'CS180');
insert into student_enrollment values (5, 'CS210');
insert into student_enrollment values (5, 'CS220');
insert into student_enrollment values (6, 'CS110');
insert into student_enrollment values (7, 'CS110');
insert into student_enrollment values (7, 'CS210');
create table professors
(
last_name varchar(20),
department varchar(12),
salary integer,
hire_date date
);
insert into professors values ('Chong', 'Science', 88000, '2006-04-18');
insert into professors values ('Brown', 'Math', 97000, '2002-08-22');
insert into professors values ('Jones', 'History', 67000, '2009-11-17');
insert into professors values ('Wilson', 'Astronomy', 110000, '2005-01-15');
insert into professors values ('Miller', 'Agriculture', 82000, '2008-05-08');
insert into professors values ('Williams', 'Law', 105000, '2001-06-05');
create table teach
(
last_name varchar(20),
course_no varchar(5)
);
insert into teach values ('Chong', 'CS180');
insert into teach values ('Brown', 'CS110');
insert into teach values ('Brown', 'CS180');
insert into teach values ('Jones', 'CS210');
insert into teach values ('Jones', 'CS220');
insert into teach values ('Wilson', 'CS110');
insert into teach values ('Wilson', 'CS180');
insert into teach values ('Williams', 'CS107');
Note that there may be multiple professors teaching the same course (and there are students enrolled in the same course more than once).
If anyone has a pointer as to what I am missing here, please let me know! I'm new to SQL and have tried a few ideas unsuccessfully.
A simple and quick way to organize the sql is to use sub clause.
select s.*, c.*
from student_enrollment se
inner join student s on se.student_no = s.student_no
inner join course c on se.course_no = c.course_no
where course_no in (select course_no from teach where last_name = 'Wilson')

How to select distinct multi-column values in Oracle SQL?

I am trying to get distinct values with multi column select.
Sample table:
CREATE TABLE DUP_VALUES (ID NUMBER, NAME VARCHAR2(64));
INSERT INTO DUP_VALUES values (1, 'TEST1');
INSERT INTO DUP_VALUES values (2, 'TEST1');
INSERT INTO DUP_VALUES values (3, 'TEST2');
INSERT INTO DUP_VALUES values (4, 'TEST2');
INSERT INTO DUP_VALUES values (5, 'TEST1');
INSERT INTO DUP_VALUES values (6, 'TEST1');
INSERT INTO DUP_VALUES values (7, 'TEST1');
I want to get
ID NAME
1 TEST1
3 TEST2
I tried with SELECT DISTINCT ID, NAME FROM DUP_VALUES
But, I got all values, because ID is unique.
Use aggregation:
select min(id) as id, name
from dup_values
group by name;

How to write a query for getting free seats in a hostel

I created a database for a hostel, I've built all tables in SQL Server, now I'm trying to write sine queries. I want to get room numbers with available free seats in them.
I have tables Students, Contracts, Rooms.
Contracts has a column Student which references the StudentId in Students and Contracts has the column Room which references the RoomId of the Rooms table. RoomId is a room number.
Room also has a column NumberSeats which is a total number of seats in the room. So I think that's enough for understanding my problem and writing a query.
I want to get room numbers with available free seats in them. I don't know how to implement this, I'm new in SQL, so all I try goes to nothing. Do you have any ideas? Thanks.
If you have all the Students mentioned by their ID in your Contracts table, you can extract data by referring just Contracts and Rooms. You can try by joining two tables, counting the number of students per room and adding a condition into the having clause:
SELECT b.RoomId,
b.NumberSeats,
COUNT(a.Student)
FROM Rooms b
LEFT JOIN Contracts a
ON a.Room=b.RoomId
GROUP BY b.RoomId,
b.NumberSeats
HAVING b.NumberSeats>COUNT(a.Student);
I've prepared this example for you.
ddl + query -->
create table student
(id number,
name varchar2(100));
create table room
(id number,
name varchar2(100));
create table contract
(student_id number,
room_id number);
create table number_seats
(room_id number,
number_seats number);
insert into student values(1, 'Jon');
insert into student values(2, 'George');
insert into student values(3, 'Ian');
insert into student values(4, 'Alex');
insert into student values(5, 'Mary');
insert into room values(1, 'room1');
insert into room values(2, 'room2');
insert into room values(3, 'room3');
insert into room values(4, 'room4');
insert into room values(5, 'room5');
insert into number_seats values(1, 1);
insert into number_seats values(2, 2);
insert into number_seats values(3, 3);
insert into number_seats values(4, 2);
insert into number_seats values(5, 1);
insert into contract values(1, 1);
insert into contract values(2, 2);
insert into contract values(3, 3);
insert into contract values(4, 4);
insert into contract values(5, 4);
select * from room;
select * from student;
select * from contract;
select * from number_seats;
select cont.room_id, num_seats.number_seats - count(*)
from student st
join contract cont on st.id=cont.student_id
join room ro on ro.id=cont.room_id
join number_seats num_seats on num_seats.room_id=ro.id
group by cont.room_id, num_seats.number_seats
union
select ro.id, num_seats.number_seats
from room ro left join contract co on ro.id=co.room_id
join number_seats num_seats on num_seats.room_id=ro.id
where co.room_id is null
order by 1;
Result is
|roomNumber|freeSeats|
| 1 | 0 |
| 2 | 1 |
| 3 | 2 |
| 4 | 0 |
| 5 | 1 |

Display 2 columns for each header

In SQL Server 2008 I have a table People (Id, Gender, Name).
Gender is either Male or Female. There can be many people with the same name.
I would like to write a query that displays for each gender the top 2 names
by count and their count, like this:
Male Female
Adam 23 Rose 34
Max 20 Jenny 15
I think that PIVOT might be used but all the examples I have seen display only one column for each header.
Here is an example on SQL Fiddle -- http://sqlfiddle.com/#!3/b3477/1
This uses an couple of common table expressions to separate the genders.
create table People
(
Id int,
Gender varchar(50),
Name varchar(50)
)
;
insert into People values (1, 'Male', 'Bob');
insert into People values (2, 'Male', 'Bob');
insert into People values (3, 'Male', 'Bill');
insert into People values (4, 'Male', 'Chuck');
insert into People values (5, 'Female', 'Anne');
insert into People values (6, 'Female', 'Anne');
insert into People values (7, 'Female', 'Bobbi');
insert into People values (8, 'Female', 'Jane');
with cteMale as
(
select Name as 'MaleName', Count(*) as Num, ROW_NUMBER() over(order by count(*) desc, Name) RowNum
from People
where Gender = 'Male'
group by Name
)
,
cteFemale as
(
select top 2 Name as 'FemaleName', Count(*) as Num, ROW_NUMBER() over(order by count(*) desc, Name) RowNum
from People
where Gender = 'Female'
group by Name
)
select a.MaleName, a.Num as MaleNum, b.femaleName, b.Num as FemaleNum
from cteMale a
join cteFemale b on
a.RowNum = b.RowNum
where a.RowNum <= 2
Use a windowing function. Below is a complete solution using a temporary table #people.
-- use temp db
use tempdb;
go
-- drop test table
--drop table #people;
--go
-- create test table
create table #people (my_id int, my_gender char(1), my_name varchar(25));
go
-- clear test table
delete from #people;
-- three count
insert into #people values
(23, 'M', 'Adam'),
(34, 'F', 'Rose');
go 3
-- two count
insert into #people values
(20, 'M', 'Max'),
(15, 'F', 'Jenny');
go 2
-- one count
insert into #people values
(20, 'M', 'John'),
(15, 'F', 'Julie');
go
-- grab top two by gender
;
with cte_Get_Top_Two as
(
select ROW_NUMBER() OVER(PARTITION BY my_gender ORDER BY count() DESC) AS my_window,
my_gender, my_name, count() as total
from #people
group by my_gender, my_name
)
select * from cte_Get_Top_Two where my_window in (1, 2)
go
Here is the output.
PS: You can drop my_id from the table since it does not relate to your problem but does not change solution.

convert marks into percentage

how to convert marks obtained by a student into x%
i.e. there are two exams. calculate certain %marks from both exams (say x% and Y%) so that the total will be 100%
Based on the limited info that you have provided, I think you might be asking for the following:
create table student
(
id int,
s_name varchar(10)
)
insert into student values (1, 'Jim')
insert into student values (2, 'Bob')
insert into student values (3, 'Jane')
create table exams
(
id int,
e_name varchar(10)
)
insert into exams values (1, 'Test 1')
insert into exams values (2, 'Test 2')
insert into exams values (3, 'Test 3')
insert into exams values (4, 'Test 4')
create table exam_student
(
e_id int,
s_id int,
dt datetime,
score decimal(5,2)
)
insert into exam_student values(1, 1, '2012-08-01', 65.0)
insert into exam_student values(1, 2, '2012-08-01', 85.0)
insert into exam_student values(2, 1, '2012-08-02', 75.0)
insert into exam_student values(2, 2, '2012-08-02', 42.0)
select avg(es.score) as ScorePct, s_id, s.s_name
from exam_student es
inner join exams e
on es.e_id = e.id
inner join student s
on es.s_id = s.id
group by s_id, s_name
Results:
If you provide more details on exactly what you are looking for that would be helpful in answering your question.