SQL-Oracle: Difficulties in resolving basic problems, part2 - sql

Problem:
The HR department needs a query that prompts the user for an employee
last name. The query then displays the last name and hire date of any employee
in the same department as the employee whose name they supply(excluding that employee).
For example, if the user enters Zlotkey, find all employees who work with
Zlotkey (excluding Zlotkey).
I managed to do this so far, but i have no clue how to finish it. For now it shows me all employees after i write the last_name excluding it. Any suggestions please how to continue?
SELECT last_name, TO_CHAR(hire_date,'DD-MON-YYYY') AS "HIRE_DATE"
FROM employees
WHERE last_name <>ALL (SELECT '&last_name'
FROM employees)
AND department_id IN (SELECT department_id
???....
P.S: This problem is from the Oracle tutorials (Oracle Database 11g: SQL Fundamentals 1 of 1 (year 2009), Practice 7 , exercise 1 for people who already done this:).

Something like this?
SELECT last_name, TO_CHAR(hire_date,'DD-MON-YYYY') AS "HIRE_DATE"
FROM employees a
JOIN (Select department_id from employees where last_name = :surname) b on a.department_id = b.department_id
and last_name <> :surname
EDIT
The only problem with this type of solution is that if there are two people with the same surname in different departments, so it might be useful to maybe use something like an employee number as a filter instead of surname.

SELECT LAST_NAME, HIRE_DATE
FROM EMPLOYEES
WHERE DEPARTMENT_ID= (SELECT DEPARTMENT_ID
FROM EMPLOYEES
WHERE LAST_NAME LIKE '&NAME')
AND LAST_NAME <> '&NAME';

Related

Get order count of employees, which have different count than in one city

SQL studying is going good speed forward. Now got practice where I need some help.
I would like to get names of the employees who have different count of orders than employees in New York.
Tables:
ORDERS, which including EMPLOYEE_ID, CITY, ORDER_ID
EMPLOYEES, which including LAST_NAME, FIRST_NAME, EMPLOYEE_ID, CITY
I have been stuck in this situation:
SELECT ROW_NUMBER() OVER ( ORDER BY COUNT(T.ORDER_ID) DESC) ROW,
(H.LAST_NAME + ', ' + H.FIRST_NAME) 'Employee name',
COUNT(T.ORDER_ID) 'Sold orders', H.CITY 'City'
FROM ORDERS T JOIN EMPLOYEE H ON T.EMPLOYEE_ID = H.EMPLOYEE_ID
GROUP BY H.EMPLOYEE_ID, H.LAST_NAME, H.FIRST_NAME, H.CITY
With that I can get orders which employees has sold. Unfortunately it does not show employees with 0 orders.
How I can show also employees with 0 orders? And how can I show employees who have different count of orders than employees in one city? Example employees which have different order coutn than employees in New York.
I hope you understand what I mean. Complicated problem and little language barrier.
Example data:
First_name Last_name Sold_orders City
John Doe 2 New York
Jane Doe 5 Los Angeles
Peter Pan 5 Miami
I would like to get employees which do not have same count of orders than employees in Miami.
First_name Last_name Sold_orders City
John Doe 2 New York
So Jane doe and Peter Pan has gone, because they have same count of orders than employees in Miami (Miami itself included).
I think that you just want a left join. For this you need to start from the employee table, then bring the orders.
select
row_number() over ( order by count(o.order_id) desc) rn,
e.last_name + ', ' + e.first_name employee_name,
count(o.order_id) sold_orders,
e.city
from employee e
left join orders o on o.employee_id = e.employee_id
group by e.employee_id, e.last_name, e.first_name, e.city
Note that I also changed the column aliases: you should avoid using single quotes. Although some databases allow this, single quotes are usually meant for string litterals rather than identifiers. Databases use different symbols to quote identifiers (Oracle and Postgres have double quotes, MySQL has backticks, SQL Server has square brackets). I changed the query so it uses identifiers that do not require quotes.

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

SQL for Mixed Case filter

I was just wondering how you would search for any mix of case. For instance, I want to find all employees with the last name 'davies', but I want to be able to find any mix of case such as 'DavIes' or 'DAVies'. This is what I've tried.
SELECT LAST_NAME
FROM EMPLOYEES
WHERE DEPARTMENT_ID = (SELECT DEPARTMENT_ID
FROM EMPLOYEES
WHERE LAST_NAME = '[Dd][Aa][Vv][Ii][Ee][Ss]');
I would use UPPER or LOWER function and IN
SELECT LAST_NAME
FROM EMPLOYEES
WHERE DEPARTMENT_ID IN (
SELECT DEPARTMENT_ID
FROM EMPLOYEES
WHERE UPPER(LAST_NAME) = 'DAVIES'
);
Unfortunately it invalidates the index use.
Using UPPER
SELECT *
FROM EMPLOYEES
WHERE UPPER(LAST_NAME) = 'DAVIES'

Unexpected result of a SQL query

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.

Give a list of all employees, fname, lname and dept, who make more than the average in their building

but only if they work in building 400, 402 or 405
Select fname, lname, dept
from Employees
where in building=400
and building=402
and building =405;
So do I find the avg then place the building of what the numbers are in the sql or, do I use the AVG() function for finding the answer? I am suppose to use subquery, but do not know how, help!
Select fname, lname, dept
from Employees
where building in (400,402,405) and salary > (select avg(salary) from Employees where building in (400, 402, 405));
Where "salary" is the column for how much the employee makes.
Also, your in statement is wrong, I have edited for you.
Out of topic question:
Are you working in HR and trying to find some executives who earns way more the others to sack them to reduce company cost?
Sounds to me like:
SELECT fname
,lname
,dept
FROM Employees a
INNER JOIN
(SELECT Building
,AVG(Salary) BuildingAvgSalary
FROM Empoyees
WHERE Building IN (400,402,405)
GROUP BY Building) b ON a.Building = b.Building
WHERE a.Salary > b.BuildingAvgSalary