SQL Average calculation - sql

Let's say there is an employer entity and it has an attribute of salary. And employer works in a department which is located in Oxford Building.(Building address is unique for building)
How can I write a SQL query that computes the average salary per building? Does it mean that salary is foreign key or what? Is it correct, if I do just
SELECT AVG(Salary) AS Averagesalary FROM Employee;
but in that case there will be no Building

That's why there's GROUP BY, to specify how you want to "group" your records. Right now you're doing an average of ALL records in table.
SELECT Building, AVG(SALARY)
FROM Employee
GROUP BY Building
The above query will also average all records, but do it per-building.

Related

Using ROUND, AVG and COUNT in the same SQL query

I need to write a query where I need to first count the people working in a department, then calculate the average people working in a department and finally round it to only one decimal place. I tried so many different variations.
That's what I got so far although it's not the first one I tried but I always get the same error message. (ORA-00979 - not a group by expression)
SELECT department_id,
ROUND(AVG(c.cnumber),1)
FROM employees c
WHERE c.cnumber =
(SELECT COUNT(c.employee_id)
FROM employees c)
GROUP BY department_id;
I really don't know what do to at this point and would appreciate any help.
Employees Table:
Try this (Oracle syntax) example from your description:
with department_count as (
SELECT department_id, COUNT(c.employee_id) as employee_count
FROM employees c
group by department_id
)
SELECT department_id,
ROUND(AVG(c.employee_count),1)
FROM department_count c
GROUP BY department_id;
But this query not make sense. Count is integer, and count return one number for one department in this case AVG return the same value as count.
Maybe you have calculate number of employee and averange of salary on department?

SQL query from Lynda.com

I have a question about two queries. Will these two queries give the same result? I am trying to find the average salary by department:
Select s1.department, avg(s1.salary)
From
(Select department, salary
From staff
Where salary > 100000) s1
Group by s1.department
vs
select department, avg(salary) as avg_salary
from staff
where salary > 100000
group by department
Yes, it gives the same amounts back.
the bottom query gets data from a sub select which gets its data from the table, whereas the top query gets it straight from the table itself.
There are no additional filters in there. So the result will be the same.
you can test it out however, don't take my word for it.

Using aggregate function for seprate rows

There is a table with name jobs where for different department number salary is giving. Same department can have more than one job so the salary may vary. Now i want to solve this query:
"Find the average salaries for each department without displaying the respective department numbers."
Here i should use avg but how to use it so that i can get my result of each department no separately?
I think what you're looking for is the GROUP BY clause. If I understand your question correctly then something like this should do the trick.
SELECT AVG(salary) FROM table_name GROUP BY department

How to calculate Standard Deviation in Oracle SQL Developer?

I have a table employees,
CREATE TABLE employees (
employeeid NUMERIC(9) NOT NULL,
firstname VARCHAR(10),
lastname VARCHAR(20),
deptcode CHAR(5),
salary NUMERIC(9, 2),
PRIMARY KEY(employeeid)
);
and I want to calculate Standard Deviation for salary.
This is the code I am using:
select avg(salary) as mean
,sqrt(sum((salary-avg(salary))*(salary-avg(salary)))/count(employeeid)) as SD
from employees
group by employeeid;
I am getting this error:
ORA-00979: not a GROUP BY expression
00979. 00000 - "not a GROUP BY expression"
*Cause:
*Action:
Error at Line: 260 Column: 12
Line 260 Column 12 is avg(salary)
How can I sort this out?
Oracle has a built-in function to calculate standard deviation: STDDEV.
The usage is as you'd expect for any aggregate function.
select stddev(salary)
from employees;
I'd just use the stddev function
SELECT avg(salary) as mean,
stddev(salary) as sd
FROM employees
It doesn't make sense to group by employeeid since that is, presumably unique. It doesn't make sense to talk about the average salary by employee, you want the average salary across all employees (or all departments or some other aggregatable unit)
The salary-avg(salary) can't be evaluated; avg(salary) is not available during execution of the query but only after all records are retrieved.
I would suggest to add AVG calculations in a subquery and JOIN it to the main one
select avg(salary) as mean,
sqrt(sum((salary-avg_res.avg)*(salary-avg_res.avg))/count(employeeid)) as SD
from employees JOIN
(select employeeid,avg(salary) as avg
from employees
group by employeeid) avg_res ON employees.employeeid=avg_res.employeeid
group by employeeid;
I thought you had to include the column in the GROUP BY in the SELECT:
select employeeid
,avg(salary) as mean
,sqrt(sum((salary-avg(salary))*(salary-avg(salary)))/count(employeeid)) as SD
from employees
group by employeeid;
But on further reflection the query doesn't make much sense unless it's historical data. An employee id ought to be unique to a single employee. Unless this is an average over time there should be only one salary per employee. Your mean will be the salary and the standard deviation will be zero.
A better query might be average of all salaries. In that case, remove the GROUP BY.
One more nitpick: the formula you're using is more properly called the population standard deviation. The sample deviation divides by (n-1).

Find all the emps and their salaries who earn minimum salary in their department, display result in salary ascending order

employee database
SELECT name, MIN(salary)
FROM employee
GROUP BY deptid;
Why I can't select "name" here?
And what is the suggested query for this question?
Why I can't select "name" here?
You can only use columns or expressions the the SELECT if they are present in the GROUP BY area, or part of a function that calculates an aggregation.
Think of grouping like buckets. When you say group by dept_id if there are 3 departments (even if they are mentioned 20 times; 20 employees in departments A,A,A,A,A,A,A,A,A,A,A,A,B,B,B,B,B,C,C,C) you get 3 buckets and there's a label on the outside of each bucket, one for each different value of dept_id (a bucket for A, a bucket for B and a bucket for C). Into those buckets, all the employees rows are thrown according to which department they're in: 12 rows in A, 5 rows in B, 3 rows in C. Then you say MIN(salary), the db searches each bucket looking for the minimum salary.
Why can't you say name? There simply isn't a bucket for it. Your buckets are labelled A, B and C for the departments. No bucket has a name written on it. While there are names inside the bucket, you can only ask for them in terms of a MIN, MAX, AVG, SUM, COUNT etc - it's the rule. "To get something out of a bucket you have to use some kind of function that calculates some statistic". Actually, in some DBs you can ask for a CSV string of all the names, but we'll ignore that because it's accessory to the main point: unless you use an aggregate function you can only ask for something written on the outside of a bucket
What information should the DB give you if you ask for name?
You could ask for MIN(name), but you'd only get one name. You could GROUP BY Name.. but then you'd have a lot more buckets, and your employees would be redistributed across the buckets. You would't be asking for the MIN salary per department bucket any more, you'd be asking for the min salary per name.. Not what you want
And what is the suggested query for this question?
Break it down:
"minimum salary in the department"
We're going to need a list of all departments and the minimum salary in the department
SELECT dept_id, MIN(salary) as min_sal_for_dept
FROM employee
GROUP BY dept_id
"Find all the emps .. who earn minimum salary in their department"
Now we know that the depatment ID and min salary is for that department, we can join it back to the employee data on the department id and the salary
SELECT *
FROM
(
SELECT dept_id, MIN(salary) as sal
FROM employee
GROUP BY dept_id
) dep_min_sals
INNER JOIN
employee e
ON
e.dept_id = dep_min_sals.dept_id AND e.salary = dep_min_sals.sal
"display result in salary ascending order"
ORDER BY sal
The key thing to realize is that you have to group up (lose) detail in order to get the minimum salary per department, so if you want the detail back you have to join the grouped up data back to the detail. You cannot both lose the detail to calculate the minimum AND also keep the detail to have the employee name
A database-independent solution is to filter with a subquery:
select e.*
from emp e
where e.salary = (select min(e1.salary) from emp e1 where e1.deptid = e.deptid)
order by e.salary