Unexpected result of a SQL query - sql

Can anyone explain why this query:
SELECT employee_id, last_name, salary
FROM employees
WHERE department_id IN (SELECT department_id
FROM employees
WHERE last_name LIKE '%u%'
)
AND salary > (SELECT AVG(salary)
FROM employees);
returns way less rows than this nested one:
SELECT employee_id, last_name, salary
FROM employees
WHERE department_id IN (SELECT department_id
FROM employees
WHERE last_name LIKE '%u%'
AND salary > (SELECT AVG(salary)
FROM employees);
)

The first returns all employees who meet the following conditions:
The employee is in a department has a "u" employee.
The employee has a salary larger than the average.
The second returns all employees who meet these conditions:
The employee is in a department that has a "u" employee who has a salary larger than the average.
The two are very different conditions. I wouldn't expect them to return the same result set.
Also, whenever you have more than one table in a query, you should use table aliases that are abbreviations of the table name and you should qualify all column names.

Related

single-row subquery returns more than one row in oracle in HR schema

select employee_id, first_name, job_id, salary
from employees where salary < ( select SALARY
FROM EMPLOYEES
WHERE JOB_ID='IT_PROG');
and I found an error like the following :
ORA-01427: single-row subquery returns more than one row
Looks like there are "many" employees whose job_id = 'IT_PROG'. In that case, subquery returns "many rows" and your query results in an error.
It depends on what you want to do in such a case; for example, you might want to return rows for employees whose salary is lower than minimum salary for IT_PROG, so that would be
SELECT employee_id,
first_name,
job_id,
salary
FROM employees
WHERE salary < (SELECT MIN (SALARY) --> note MIN function here
FROM EMPLOYEES
WHERE JOB_ID = 'IT_PROG');

Cannot get results to show when querying salary of department based on average salary of department and twice minimum salary of entire company

I am attempting to display the department and average salary of employees in said department if it meets a condition: average salary of department must be twice the minimum salary of the entire firm.
select dname, avg(salary) from department, employee where dno=dnumber group by dname having avg(salary) > min(salary)*2;
I have tables for employee, department. My query is below, however it results in an empty table.
I believe it is because salary in the halving clause is referencing within department and within employee - or rather it isn't doing this properly.
To just list average salaries by department I used this query which seems to work fine:
select dname, avg(salary) from department, employee where dno=dnumber group by dname;
Any help would be much appreciated.
Thank you!
min(salary) is the minimum of the department, replace it with (select min(salary) from employee)

Oracle SQL sub query

I have a practice that I should find the employees who earn more than average salary and works in the departments with employees whose last name contains the letter u
the select statement I have used was
SELECT employee_id,
last_name,
salary
FROM employees
WHERE salary > (SELECT AVG(salary)
FROM employees )
AND department_id IN(SELECT department_id
FROM employees
WHERE LOWER(last_name) LIKE '%u%')
Could anyone check this statement is suitable or not ?
thank you
That looks fine to me, assuming you mean the average salary across all departments in the database, and all employees (active or not) across all of time.
I would think you might be more interested in all active employees in this current financial year, for example.
You haven't provided the schema, so be careful to check for conditions like:
inactive departments
inactive / terminated employees
period you are interested in for comparing the salary
Your queries looks like it will work. You can rewrite it to remove all the sub-queries (that will require additional table/index scans) and just use analytic queries:
SELECT employee_id,
last_name,
salary
FROM (
SELECT employee_id,
last_name,
salary,
AVG( salary ) OVER () AS avg_salary,
COUNT( CASE WHEN LOWER( last_name ) LIKE '%u%' THEN 1 END )
OVER ( PARTITION BY department_id ) AS num_last_name_with_u
FROM employees
)
WHERE salary > avg_salary
AND num_last_name_with_u > 0;
db<>fiddle
My first Question are you getting the expected result ?
Let me break down your Query
SELECT department_id FROM employees WHERE LOWER(last_name)
Here you are selecting the department so it retrieve the department id, what is the need of selecting department Id when all you need employee_id with last name contains u so change it to employee_id instead of department_id
select avg(salary) over (partition by department_id order by employee_id)
So using partition by you must get the avg salary per department
SELECT employee_id,last_name,salary
FROM
employees
WHERE salary>(SELECT AVG(salary) OVER (PARTITION BY department_id)
FROM
employees )
AND employee_id IN
( SELECT employee_id
FROM
employees
WHERE LOWER(last_name) LIKE '%u%')
Let me know if you have any issues running it, any corrections to Query is appreciated

Display salary, Avg(salary), Name for those who earns more than company Avg(salary)

how to display the name, salary and the avg(salary) for all the employees whose salary is greater than the company avg(salary).
I have tried the following query:
Select last_name, salary
From employees
Where salary >(select avg(salary) from employees);
This gives the names of those employees who are getting higher salary than the company avg(salary). But I want to display the avg(salary) in the select list aswell.
Join the employee table to a query that produces the average:
select last_name, salary, avg_salary
from employees
join (select avg(salary) avg_salary from employees) x
on salary > avg_salary
This query will work on all databases.
Assuming sql server, here is but one of many ways to accomplish this:
DECLARE #AverageSalary MONEY
SELECT #AverageSalary=AVG(SALARY) FROM EMPLOYEES
Select last_name, salary, #AverageSalary From employees Where salary > #AverageSalary

Using the MIN function in the having clause

I want to get the name of the employee who has the minimum salary. Is there a way to do this using only one query? I have given my query below, it doesn't work because the having clause requires a condition. Is there any way to give a condition in the having clause that will retreive the employee name with the minimum salary?
SELECT first_name,min(salary) as "sal"
FROM Employees
GROUP BY first_name
having min(salary);
How about using ROWNUM?
SELECT *
FROM(SELECT first_name, salary
FROM Employees
ORDER BY salary
) WHERE ROWNUM = 1
SELECT first_name, salary as "sal"
FROM employees
WHERE salary =(SELECT MIN(salary)
FROM employees);
Try this solution, inspired from here:
SELECT e1.first_name, e1.salary AS "sal"
FROM Employees e1
LEFT OUTER JOIN Employees e2
ON (e1.id <> e2.id AND e1.salary > e2.salary)
WHERE e2.id IS NULL;
With a single SELECT statement:
SELECT MIN( first_name ) KEEP ( DENSE_RANK FIRST ORDER BY salary ASC, first_name ASC ) AS first_name,
MIN( salary ) KEEP ( DENSE_RANK FIRST ORDER BY salary ASC, first_name ASC ) AS salary
FROM Employees;
SQLFIDDLE
However, if there are multiple people with the same minimum salary then this will only get the one with the name which is first alphabetically.
You can get all the names, but it does require multiple SELECT statements:
SELECT first_name, salary
FROM Employees
WHERE salary = ( SELECT MIN(salary) FROM Employees );
But having multiple SELECT statements isn't a bad thing.
SQLFIDDLE
SELECT TOP 1 WITH TIES *
FROM employees
ORDER BY salary ASC
If you need the employee with the lowest salary why don't you use Order By ..
SELECT top 1 first_name,min(salary) as LowestSalary
FROM Employees order by Salary asc
SELECT first_name,min(salary) as "sal"
FROM Employees
GROUP BY first_name
having min(salary) >0;
If you want to do this with only one query, while also retrieving all employees with the minimum salary (example: you have a minimum salary of $40,000, but two employees have this exact salary) you could join the table with itself. This solution also uses the 'having' clause that you included in your original question.
SELECT e.first_name,e.salary AS "sal"
FROM Employees e, Employees e2
GROUP BY first_name
HAVING MIN(e2.salary)=e.salary;