Find the manager_id with most people under supervision - sql

I am having trouble displaying the most people under manager_id. The answer is manager_id = 100 but I can't seem to make a sql that displays it. Below are 2 tables that were created and given to me.
CREATE TABLE departments
( department_id NUMBER(4)
, department_name VARCHAR2(30)
CONSTRAINT dept_name_nn NOT NULL
, manager_id NUMBER(6)
, location_id NUMBER(4)
) ;
CREATE TABLE employees
( employee_id NUMBER(6)
, first_name VARCHAR2(20)
, last_name VARCHAR2(25)
CONSTRAINT emp_last_name_nn NOT NULL
, email VARCHAR2(25)
CONSTRAINT emp_email_nn NOT NULL
, phone_number VARCHAR2(20)
, hire_date DATE
CONSTRAINT emp_hire_date_nn NOT NULL
, job_id VARCHAR2(10)
CONSTRAINT emp_job_nn NOT NULL
, salary NUMBER(8,2)
, commission_pct NUMBER(2,2)
, manager_id NUMBER(6)
, department_id NUMBER(4)
, CONSTRAINT emp_salary_min
CHECK (salary > 0)
, CONSTRAINT emp_email_uk
UNIQUE (email)
) ;
Below is my code where I am trying to join the two tables employees and departments together to find manager_id between them with the most occurrence.
Every time I try to run my sql block it gives me an error like "ORA-00918: column ambiguously defined" or something is wrong with Limit 1
SELECT COUNT(Manager_id) into v_manager_id,
FROM departments d
RIGHT JOIN employees e
ON d.manager_id = e.manager_id
GROUP BY Manager_id
ORDER BY COUNT(Manager_id) DESC
LIMIT 1;

You should rather select count(employee_id) ... group by manager_id so for all employees who are under some manager that count is displayed and then check if that count is max under that manager or not
else it is alias or qualifier issue you should name manager_id as some alias.

this will work:
select manager_id
from (select manager_id,count(*)
from employees
group by manager_id
order by
count(*) desc)
where rownum<=1 ;
you can also use nested subquery like this:
create table ns_231(col1 number,col2 number);
insert into ns_231 values(1,1);
insert into ns_231 values(2,3);
insert into ns_231 values(3,3);
insert into ns_231 values(1,2);
insert into ns_231 values(2,5);
insert into ns_231 values(2,1);
insert into ns_231 values(3,1);
insert into ns_231 values(1,4);
SELECT * FROM ns_231;
commit;
select col1 from (select col1,count(*) from ns_231 group by col1 order by count(*) desc) where rownum<=1 ;
select col1 from ns_231 group by col1
having count(*)=(select max(total) from (select count(*) as total from
ns_231 group by col1));
output:
1
2
for your table the query is :
select manager_id from employees group by manager_id
having count(*)=(select max(total) from (select count(*) as total from
employees group by manager_id));

I think you need to add qualifier to manager_id because it occurs in both tables
SELECT COUNT(d.Manager_id) into v_manager_id,
FROM departments d
RIGHT JOIN employees e
ON d.manager_id = e.manager_id
GROUP BY d.Manager_id
ORDER BY COUNT(d.Manager_id) DESC
LIMIT 1;

Related

how to find less than the largest number in sql?

i want to show the salaries less than the largest number in the table
create table instructor(
ID number not null ,
name varchar(20) ,
dept_name varchar(25),
salary number,
primary key (ID)
);
insert into instructor values('10101', 'sirinvasan' , 'comp csi' , '65000');
insert into instructor values('12121', 'wu' , 'finance' , '90000');
insert into instructor values('15151', 'mozart' , 'music' , '40000');
insert into instructor values('22222', 'einstein' , 'physics' , '95000');
insert into instructor values('32343', 'el said' , 'history' , '60000');
i tried using
select distinct T.salary
from instructor as T , instructor as S
where T.salary < S.salary
but it gives me this error ORA-00933: SQL command not properly ended
You can do it in a single table scan using analytic functions:
SELECT salary
FROM (
SELECT DISTINCT
salary,
DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
FROM instructor
)
WHERE rnk > 1
Or, if you want to use a sub-query:
SELECT DISTINCT
salary
FROM instructor
WHERE salary NOT IN (SELECT MAX(salary) FROM instructor);
db<>fiddle here
Try this
Select salary from table where salary < (Select
max(salary) from table)
There are many ways to do this. Here is another one.
with a as (
select salary
, max(salary) over () as maxsalary
from instructor
)
select distinct salary
from a
where salary < maxsalary
In the name of completeness, here is another viable answer:
SELECT DISTINCT i.salary
FROM instructor i
ORDER BY i.salary DESC
OFFSET 1 ROW;
I actually like the simplicity of this one. It is just ordering the query and skipping the first row. No analytic functions necessary.
DBFiddle Here: (LINK)

Oracle recursive CTE to check consecutive date rows

In trying to make use of a recursive common table expressions and lead analytical function that checks for 'N>1'
consecutive absent_dates but seem to be struggling.
Note I know the employees table isn't included in the query yet to obtain first_name and last_name as I am trying to keep the test case as simple as possible.
Below is my test CASE.
The desired output should be as follows:
EMPLOYEE_ID ABSENT_DATE
1 14-JUL-21 Jane Doe
1 15-JUL-21 Jane Doe
1 30-JUL-21 Jane Doe
1 31-JUL-21 Jane Doe
4 22-JUL-21 Mike Jones
4 23-JUL-21 Mike Jones
Create table employees(
employee_id NUMBER(6),
first_name VARCHAR2(20),
last_name VARCHAR2(20),
card_num VARCHAR2(10),
work_days VARCHAR2(7)
);
ALTER TABLE employees
ADD ( CONSTRAINT employees_pk
PRIMARY KEY (employee_id));
INSERT INTO employees
(
EMPLOYEE_ID,
first_name,
last_name,
card_num,
work_days
)
WITH names AS (
SELECT 1, 'Jane', 'Doe','F123456', 'NYYYYYN'FROM dual UNION ALL
SELECT 2, 'Madison', 'Smith','R33432','NYYYYYN'
FROM dual UNION ALL
SELECT 3, 'Justin', 'Case','C765341','NYYYYYN'
FROM dual UNION ALL
SELECT 4, 'Mike', 'Jones','D564311','NYYYYYN' FROM dual )
SELECT * FROM names;
create table absences(
seq_num integer GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
employee_id NUMBER(6),
absent_date DATE,
constraint absence_chk check (absent_date=trunc(absent_date, 'dd')),
constraint absence_pk primary key (employee_id, absent_date)
);
begin
insert into absences values (1,1, date'2021-07-21');
insert into absences values (2,4, date'2021-07-22');
insert into absences values (3,4, date'2021-07-23');
insert into absences values (4,4, date'2021-07-26');
insert into absences values (5,1, date'2021-07-30');
insert into absences values (6,1, date'2021-07-31');
insert into absences values (7,4, date'2021-07-13');
insert into absences values (8,1, date'2021-07-14');
insert into absences values (9,1, date'2021-07-15');
commit;
end;
-- Different solutions to answer my question
WITH multi_day as (
-- Uses tabibitosan method to look for sequential groups
select employee_id
,absent_date
-- tabibitosan... date-row number gives a constant value (in this case date)
-- where the dates are sequential
,absent_date-row_number() over (partition by employee_id order by absent_date) as grp
from absences
order by. employee_id, absent_date
)
select. m.employee_id
,e.first_name
,e.last_name
,min(m.absent_date) as start_of_absence
,max(m.absent_date) as end_of_absensce
,count(*) as days_absent
from multi_day m
join employees e on (e.employee_id = m.employee_id)
group by m.employee_id
,m.grp
,e.first_name
,e.last_name
having count(*) > 1
order by 1,2;
WITH tab as (
-- Uses tabibitosan method to look for sequential groups
select employee_id
,absent_date
-- tabibitosan... date-row number gives a constant value (in this case date)
-- where the dates are sequential
,absent_date-row_number() over (partition by employee_id order by absent_date) as grp
from absences
)
,multi_day as (
select employee_id
,absent_date
,count(*) over (partition by employee_id, grp) as grp_cnt
from tab
)
select m.employee_id
,e.first_name
,e.last_name
,m.absent_date
from multi_day m
join employees e on (e.employee_id = m.employee_id)
where grp_cnt > 1
order by 1,2;
WITH consecutive_absences AS
(
SELECT a.absent_date,
a.employee_id,
e.first_name,
e.last_name,
LEAD (a.absent_date) OVER ( PARTITION BY a.employee_id
ORDER BY a.absent_date
) AS next_date
, LAG (a.absent_date) OVER ( PARTITION BY a.employee_id
ORDER BY a.absent_date
) AS prev_date
FROM absences a
join employees e on (e.employee_id = a.employee_id)
)
SELECT employee_id,
first_name,
last_name,
absent_date
FROM consecutive_absences
ORDER BY employee_id, absent_date;
SELECT a.employee_id, a.absent_date
, e.first_name, e.last_name
FROM absences
MATCH_RECOGNIZE
(
PARTITION BY employee_id
ORDER BY absent_date
ALL ROWS PER MATCH
PATTERN (frst nxt +)
DEFINE nxt AS absent_date <= PREV (absent_date) + 1
) a
JOIN employees e ON e.employee_id = a.employee_id
ORDER BY employee_id, absent_date
;
You needn't recursion. Query absences using lead/lag
select *
from (
select a.*, lead(absent_date) over(partition by employee_id order by absent_date) nxt,
lag(absent_date) over(partition by employee_id order by absent_date) prev
from absences a
) t
where absent_date = prev + 1 or absent_date = nxt - 1;
Then join this to employees.

Need to resolve an SQL query error

CREATE TABLE DEPARTMENTS
( DEPARTMENT_ID NUMERIC(4,0),
"DEPARTMENT_NAME" VARCHAR(30 ) CONSTRAINT DEPT_NAME_NN NOT NULL ,
"MANAGER_ID" NUMERIC(6,0),
"LOCATION_ID" NUMERIC(4,0),
);
CREATE TABLE EMPLOYEES
( EMPLOYEE_ID NUMERIC(6,0),
FIRST_NAME VARCHAR(20 ),
LAST_NAME VARCHAR(25 ) CONSTRAINT "EMP_LAST_NAME_NN" NOT NULL ,
EMAIL VARCHAR(25 ) CONSTRAINT "EMP_EMAIL_NN" NOT NULL ,
PHONE_NUMBER VARCHAR(20 ),
HIRE_DATE DATE CONSTRAINT "EMP_HIRE_DATE_NN" NOT NULL ,
JOB_ID VARCHAR(10 ) CONSTRAINT "EMP_JOB_NN" NOT NULL ,
SALARY NUMERIC(8,2),
COMMISSION_PCT NUMERIC(2,2),
MANAGER_ID NUMERIC(6,0),
DEPARTMENT_ID NUMERIC(4,0),
);
I need to list the name of the department, average salary and number of employees working in that department who got commission.
SELECT DEPARTMENT_NAME, AVG(SALARY), COUNT(COMMISSION_PCT)
FROM DEPARTMENTS JOIN EMPLOYEES USING (DEPARTMENT_ID);
GROUP BY DEPARTMENT_NAME
This is what I've got so far, but it gives me an error:
"DEPARTMENT_ID" is not a recognized table hints option. If it is intended as a parameter to a table-valued function or to the CHANGETABLE function, ensure that your database compatibility mode is set to 90.
I don't know which DBMS did you use.
I think that will be work,when you use INNER JOIN instead of USING
SELECT DEPARTMENT_NAME, AVG(SALARY), COUNT(COMMISSION_PCT)
FROM DEPARTMENTS
INNER JOIN EMPLOYEES on DEPARTMENTS.DEPARTMENT_ID = EMPLOYEES.DEPARTMENT_ID
GROUP BY DEPARTMENT_NAME;

Better idea to select unique data from table

I am learning SQL. I want to select employee (emp_name, emp_lname, project_name) which has only one project (not more or less).
I have 3 table in database:
Tables:
create table employee(
emp_id char (5) primary key,
emp_name nvarchar(15) not null,
emp_lname nvarchar(20)
);
create table project(
pr_id char(5) primary key,
project_name nvarchar(10) not null,
project_budjet int
);
create table employee_project(
emp_id char (5) foreign key references employee(emp_id),
pr_id char(5) foreign key references project(pr_id),
constraint premppk primary key(emp_id, pr_id)
);
I am trying to select only unique emp_id from employee_project.
This code gives me unique emp_id from employee_project
select emp_id, count(pr_id) from employee_project
group by emp_id having count(pr_id) = 1
But I need emp_id and pr_id to select emp_name, emp_lname and project_name. I try to select pr_id too using emp_id what I have already. Code:
select ep.emp_id, ep.pr_id from employee_project as ep,
(
select emp_id, count(pr_id) from employee_project
group by emp_id having count(pr_id) = 1
) CT
where CT.emp_id = ep.emp_id
Now I have everything to select everything what I need about these employee and project. Finally code:
select employee.emp_name, employee.emp_lname, project.project_name
from employee, project,
(
select ep.emp_id, ep.pr_id from employee_project as ep,
(
select emp_id, count(pr_id) from employee_project
group by emp_id having count(pr_id) = 1
) CT
where CT.emp_id = ep.emp_id
) CK
where CK.emp_id = employee.emp_id and CK.pr_id = project.pr_id
Is there any way to do this easily.
Thanks for help.
Since there is only one project you are looking for you can use any aggregate function in the group to get the project too. I used min(pr_id) but you could also use avg() or max() for instance.
After that you can join the tables to get all the other column values.
select e.*, p.*
from
(
select emp_id, min(pr_id) as pr_id
from employee_project
group by emp_id
having count(pr_id) = 1
) ep
join employee e on e.emp_id = ep.emp_id
join project p on p.pr_id = ep.pr_id

Oracle SQL query issue

I am using oracle's SQL Developer. To begin with, I have this table:
Name Null Type
-------------- -------- ------------
EMPLOYEE_ID NOT NULL NUMBER(6)
FIRST_NAME VARCHAR2(20)
LAST_NAME NOT NULL VARCHAR2(25)
DEPARTMENT_ID NUMBER(4)
I would like to retrieve(select) the ID of the department in which are the most employees.
I managed through a statement to retrieve all the numbers of the employees in every department:
select count(employee_id), department_id
from employees
group by department_id;
It gives me something like:
count(employee_id) | department_id
---------------------|------------------
6 100
16 30
1 12
What I would like to do is ONLY to retrieve the department_id 30, which (in this case) has the most employees.
A typical way to do this in Oracle:
select department_id
from (select count(employee_id), department_id
from employees
group by department_id
order by count(employee_id) desc
) t
where rownum = 1;
If you have potential duplicates and want all the department ids, then a join to the max or analytic function is a better approach. For example:
select department_id
from (select count(employee_id), department_id,
rank() over (order by count(employee_id) desc) as seqnum
from employees
group by department_id
) t
where seqnum = 1;