Count on a database using Count function SQL - sql

I have the database schema like this
Flights(flno,from,to,distance,departs,arrives,price)
Aircraft(aid,aname,cruisingRange)
Certified(employee,aircraft)
Employees(eid,ename,salary)
Where Flno is primary key and Each route corresponds to a "flno".
So I have this question to answer for the Schema
For each pilot, list their employee ID, name, and the number of routes
he can pilot.
I have this SQL, is this correct? ( I can test, as I dont have data for the database).
select eid, ename, count(flno)
from employees, flights
groupby flno

This is a simple questioin, but as everyone is mentioning you don't have any link between employee and flights. The relationships stop at certified.
You obviously have or will create some relationship. I have written a query that will give you the count taking into account that you will have a many to many relationship between employee and flights. Meaning an employee can have many flights and a single flight can be made by many employees.
Flights(flno,from,to,distance,departs,arrives,price)
Aircraft(aid,aname,cruisingRange)
Certified(employee,aircraft)
Employees(eid,ename,salary)
select
e.eid employee_id,
e.ename employee_name,
count(*)
from
employees e
inner join certified c on
c.employee = e.eid
inner join aircraft a on
a.aid = c.aircraft
inner join aircraft_flights af on -- new table that you would need to create
af.aircraft = a.aid and
inner join flights f on
f.flno = af.flno -- not I made up a relationship here which needs to exist in some for or another
group by
e.eid,
e.ename
I hope this at least shows you how to write a count statement correctly, but you should probably brush up on your understanding of joins.
Hope that helps.
EDIT
Without the relationships and working in your comments you could get the count as below.
select
e.eid employee_id,
e.ename employee_name,
count(*)
from
employees e
inner join certified c on
c.employee = e.eid
inner join aircraft a on
a.aid = c.aircraft
inner join flights f on
f.distance <= a.cruisingRange
group by
e.eid,
e.ename

Related

subquery and join not giving the same result

1
select *
from employees
where salary > (select max(salary) from employees where department_id=50)
2
select *
from employees e left join
employees d
on e.DEPARTMENT_ID =d.DEPARTMENT_ID
where d.salary > (select max(salary) from employees where department_id=50)
why the second query is giving multiple record
i want achieve the same result as of 1st query using join.....
Thanks in Advance......
Rocky, the first select is correct. Why do you want to do any join? Without further information the objective of the second select is not clear (nonsense).
I can't see the point about joining against the same table by DEPARTMENT_ID. Anyway, the problem about duplicates is because you are joining the same two tables by a key is not pk, basically you are multiplyng each employee for all the employees of the same department. This version eliminate duplicates but still has no improvement from the first one.
select *
from employees e left join
employees d
on e.employee_ID = d.employee_ID
where d.salary > (select max(salary) from employees where department_id=50)
You are probably looking for an anti join. This is a pattern mainly used in a young DBMS where IN and EXISTS clauses are slow compared to joins, because the developers focused on joins only.
You are looking for all employees whose salaries are greater than all salaries in department 50. With other words: WHERE NOT EXISTS a salary greater or equal in department 50.
Your query can hence be written as:
select *
from employees e
where not exists
(
select null
from employees e50
where e50.department_id = 50
and e50.salary >= e.salary
);
As an anti join (an outer join where you dismiss all matches):
select *
from employees e
left join employees e50 on e50.department_id = 50 and e50.salary >= e.salary
where e50.salary is null;

JOIN - 2 tasks - sql developer

I have 2 tasks:
1. FIRST TASK
Show first_name, last_name (from employees), job_title, employee_id (from jobs) start_date, end_date (from job_history)
My idea:
SELECT s.employee_id
, first_name
, last_name
, job_title
, employee_id
, start_date
, end_date
FROM employees
INNER JOIN jobs hp
on s.employee_id = hp.employee_id
INNER JOIN job_history
on hp.jobs = h.jobs
I know it doesn't work. I'm receiving: "HP"."EMPLOYEE_ID": invalid identifier
What does it mean "on s.employee_id = hp.employee_id". Maybe I should write sthg else instead of this.
2. SECOND TASK
Show department_name (from departments), average and max salary for each department (those data are from employees) and how many employees are working in those departments (from employees). Choose only departments with more than 1 person. The result round to 2 decimal places.
I have the pieces, but i don't know to connect it
My idea:
SELECT department_name,average(salary),max(salary),count(employees_id)
FROM employees
INNER JOIN departments
on employees_id = departments_id
HAVING count(department) > 1
SELECT ROUND(average(salary),2) from employees
I modified your queries a bit by improving table aliasing. Hopefully, if the right columns are present in the tables as you say, it should work:
SELECT s.employee_id, s.first_name, s.last_name,
hp.job_title, hp.employee_id,
h.start_date, h.end_date
FROM employees s
INNER JOIN jobs hp
on s.employee_id = hp.employee_id
INNER JOIN job_history h
on hp.jobs = h.jobs;
When we say on s.employee_id = hp.employee_id it means that if, for example, there is an employee_id = 1234 present in both the tables employees and jobs, then SQL will bring all the columns from both the tables in the same line that corresponds to employee_id = 1234. You can now pick different columns in the SELECT clause as if they are in the same/single table(which was not the case before joining). This is the main logic behind SQL joins.
As to your 2nd task, try the below query. I made some modifications in aggregation by introducing COUNT(DISTINCT s.employees_id). If the same employees_id is present twice for some reason, you still want to count that as one person.
SELECT d.department_name, avg(s.salary), max(s.salary), count(distinct s.employees_id)
FROM employees s
INNER JOIN departments d
on e.employees_id = d.departments_id
GROUP BY d.department_name
HAVING COUNT(DISTINCT s.employees_id) > 1;
Let me know if there is still any issue. Hopefully, this works.

SQL query returns student id, course section id, and grade when section id 1000

Using Oracle Apex Browser, image of database
http://imgur.com/a/Hhblp#0
select s_ID, c_sec_ID, grade
from s_ID.ID, c_sec_ID.csID, grade.ID, grade.csID
where c_sec_ID = 1000
^ All I think of and I'm not sure if I'm suppose to join them together or group them either.
You have to join these tree tables COURSE_SECTION, ENROLLMENT and STUDENT to get desired output. Put INNER JOIN on three tables and add
Where Clause to filter records.
You can try this
SELECT S.s_ID, C.c_sec_ID, E.grade
FROM COURSE_SECTION C INNER JOIN ENROLLMENT E ON C.C_SEC_ID = E.C_SEC_ID
INNER JOIN STUDENT S ON S.S_ID = E.S_ID
WHERE C.C_SEC_ID = 1000

avg operation on repeated values

I have two tables, employee and certified.
The certified table contains the list of employees certified to drive a plane. One employee may be certified for many planes and vice versa. Not all employees are certified.
Each employee draws a salary. Only one salary, no matter how many certifications.
How do i find the average salary of those employees who are certified for at least one plane?
My problem is,
SELECT AVG(SALARY) FROM EMPLOYEE E, CERTIFIED C WHERE E.EID=C.EID;
This includes a salary twice if the employee is certified for two planes. So AVG(salary) gives a wrong value.
I'm a newbie, so my apologies if my question seems too basic. Help?
You want a semi-join here. You can implement it with an IN predicate:
SELECT AVG(SALARY)
FROM EMPLOYEE
WHERE EID IN (
SELECT EID
FROM CERTIFIED
)
;
or with an EXISTS predicate:
SELECT AVG(e.SALARY)
FROM EMPLOYEE AS e
WHERE EXISTS (
SELECT *
FROM CERTIFIED AS c
WHERE c.EID = e.EID
)
;
The IN predicate will not work as expected if CERTIFIED.EID is nullable and indeed has nulls, although I would assume it would be unusual to store a certification in that table not associated with any employee.
Alternatively you could use a proper join (and I would recommend you seriously consider switching to the proper join syntax too), only you would need to join to a set of distinct EID values derived from CERTIFIED, rather than directly to CERTIFIED. For the derived table you can use DISTINCT:
SELECT AVG(e.SALARY)
FROM EMPLOYEE AS e
INNER JOIN (
SELECT DISTINCT EID
FROM CERTIFIED
) AS c
ON e.EID = c.EID
;
or GROUP BY:
SELECT AVG(e.SALARY)
FROM EMPLOYEE AS e
INNER JOIN (
SELECT EID
FROM CERTIFIED
GROUP BY EID
) AS c
ON e.EID = c.EID
;
If an employee can have only one salary, I suggest
SELECT AVG(e.salary)
FROM employee e
WHERE e.id in (SELECT c.id FROM certified c)
This makes sure, that each eid is taken once. I still do not understand what the certified table is doing here. Do you need only those salaries of employees which are certified for flights?

SQL query returning cartesian product

I have some tables:
Employee: id, name, id_suc, id dep, id_sec
Suc : id_suc, name
Dep : id_dep, id_suc, name
Sec : id_sec, id_dep, id_suc, name
Don't blame on me, this is an existing application, I didn't create the Database and can't touch the structure since there is too much data inside and reports depending on it. I'm just trying to modify a report as asked.
I do a query:
SELECT DISTINCT
s.name as sucurs,
d.name as depart,
c.name as section,
e.name AS emp
FROM
employee e
join suc s on (e.id_suc = s.id_suc)
join dep d on (e.id_dep = d.id_dep)
join sec c on (e.id_sec = c.id_sec)
ORDER BY
sucurs, depart, section, emp
and brings me a cartesian product. I want:
sucurs1, depart1, section1, emp1
sucurs1, depart1, section1, emp2
.....
(then on the report I group by suc, then dep, then sec)
instead, I got:
sucurs1, depart1, section1, emp1
sucurs2, depart1, section1, emp1
and so on. It brings ALL sucurs, ALL depart, ALL section and sometimes duplicated emp.
I'm missing something, but don't know what. Any clues?
Well, you're always joining the tables to only employee - it would seem that Dep is also linked to Suc - so you need a second JOIN condition (join not only on id_dep but also on id_suc!). Table Sec even needs three JOIN conditions since it shares three id's with the Employee table.
SELECT DISTINCT
s.name as sucurs,
d.name as depart,
c.name as section,
e.name AS emp
FROM
employee e
INNER JOIN
suc s ON e.id_suc = s.id_suc
INNER JOIN
dep d ON e.id_dep = d.id_dep AND e.id_suc = d.id_suc
INNER JOIN
sec c ON e.id_sec = c.id_sec AND e.id_suc = c.id_suc AND e.id_dep = c.id_dep
ORDER BY
sucurs, depart, section, emp