Oracle Hierarchical queries with views and joins - sql

I have a table setup like this:
create table DEP
(
depid NUMBER,
name VARCHAR2(200),
manager NUMBER
);
create table EMP
(
empid NUMBER,
depid NUMBER,
name VARCHAR2(200),
role VARCHAR2(200),
salary NUMBER,
manager NUMBER
);
insert into dep (DEPID, NAME, MANAGER)
values (1, 'IT', 2);
insert into dep (DEPID, NAME, MANAGER)
values (2, 'ACCOUNTING', 4);
insert into dep (DEPID, NAME, MANAGER)
values (3, 'MARKETING', 5);
insert into emp (EMPID, DEPID, NAME, ROLE, SALARY, MANAGER)
values (1, 1, 'KEVIN', 'PROGRAMMER', 20000, 2);
insert into emp (EMPID, DEPID, NAME, ROLE, SALARY, MANAGER)
values (2, 1, 'LOUIS', 'ANALYST', 30000, null);
insert into emp (EMPID, DEPID, NAME, ROLE, SALARY, MANAGER)
values (3, 2, 'RACHEL', 'CASHER', 15000, 4);
insert into emp (EMPID, DEPID, NAME, ROLE, SALARY, MANAGER)
values (4, 2, 'JOHN', 'ECONOMIST', 50000, null);
insert into emp (EMPID, DEPID, NAME, ROLE, SALARY, MANAGER)
values (5, 3, 'ERNEST', 'WRITER', 22000, null);
insert into emp (EMPID, DEPID, NAME, ROLE, SALARY, MANAGER)
values (6, 3, 'JACK', 'COMMUNITY MANAGER', 18000, 5);
Then I create these two equivalent views
create or replace view depemp1 as
with v as (
select emp.empid, dep.depid, dep.name depname, emp.name, emp.role, emp.salary,emp.manager
from emp, dep
where emp.depid = dep.depid
)
select v1.empid v1_empid, v1.depid v1_depid, v1.depname v1_depname, v1.name v1_name, v1.role v1_role, v1.salary v1_salary,v1.manager v1_manager
,v2.empid v2_empid, v2.depid v2_depid, v2.depname v2_depname, v2.name v2_name, v2.role v2_role, v2.salary v2_salary,v2.manager v2_manager
from v v1 ,v v2
where v1.empid = v2.empid
create or replace view depemp2 as
select emp1.empid v1_empid, dep1.depid v1_depid, dep1.name v1_depname, emp1.name v1_name, emp1.role v1_role, emp1.salary v1_salary,emp1.manager v1_manager
,emp2.empid v2_empid, dep2.depid v2_depid, dep2.name v2_depname, emp2.name v2_name, emp2.role v2_role, emp2.salary v2_salary,emp2.manager v2_manager
from emp emp1, emp emp2, dep dep1, dep dep2
where emp1.depid = dep1.depid and emp2.depid = dep2.depid
and emp2.empid = emp1.empid
If I select from them I can check it.
select * from depemp1;
select * from depemp2;
Now lets consider the next query to depemp1:
select
level,
depemp1.*
from depemp1
connect by prior v1_empid = v1_manager
start with v1_manager is null
The query above gives no result. Nevertheless, the same query to depemp2 (that gives the same rows and data than depemp1) gives 6 rows.
select
level,
depemp2.*
from depemp2
connect by prior v1_empid = v1_manager
start with v1_manager is null
I am using Oracle 10g and I don't understand why is this behaviour. I think this hierarchical query works on the same data output from depemp1 and depemp2 and should give the same result.

Related

How to know departments without male employes

We have two tables
Department
Emp
Department
CREATE TABLE department
(
deptno int NOT NULL,
dname varchar2(50) NOT NULL,
loc varchar2(13)
);
INSERT INTO DEPT (DEPTNO, DNAME, LOC)
VALUES (10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO DEPT (DEPTNO, DNAME, LOC)
VALUES (20, 'RESEARCH', 'DALLAS');
INSERT INTO DEPT (DEPTNO, DNAME, LOC)
VALUES (30, 'SALES', 'CHICAGO');
INSERT INTO DEPT (DEPTNO, DNAME, LOC)
VALUES (40, 'OPERATIONS', 'BOSTON');
CREATE TABLE emp
(
empno number(4,0),
ename varchar2(10),
sex varchar2(10),
deptno number(2,0)
)
INSERT INTO emp
VALUES (7839, 'KING', 'PRESIDENT', Male, 10);
INSERT INTO emp
VALUES (7898, 'BLAKE', 'MANAGER', Male, 30);
INSERT INTO emp
VALUES (7782, 'CLARK', 'MANAGER', Female, 10);
INSERT INTO emp
VALUES (7566, 'JONES', 'ANALYST', Female, 20);
INSERT INTO emp
VALUES (7788, 'SCOTT', 'ANALYST', Male, 20);
INSERT INTO emp
VALUES (7902, 'FORD', 'ANALYST', Male, 20);
INSERT INTO emp
VALUES (7369, 'SMITH', 'CLERK', Female, 20);
INSERT INTO emp
VALUES (7369, 'Allen', 'Manager', Male, 40);
COMMIT;
Need a list of departments without a female employee....
Thanks
Raju
I got a list of departments with female employees and removed them from the entire list.
select deptno
from emp
where deptno not in (select deptno
from emp
where sex = 'Female');
I wanted to know if there is a better way to do it
You can use NOT EXISTS:
select *
from dept
where not exists (
select 1 from emp where emp.deptno = dept.deptno and emp.sex = 'Female'
)
Or the easier to read NOT IN, though probably less performant:
select *
from dept
where deptno not in (select deptno from emp where sex = 'Female')
Something like
SELECT
deptno,
sum(CASE sex WHEN 'Female' THEN 1 ELSE 0 END) AS number_female
FROM emp
GROUP BY deptno;
might work. You would need to select those department numbers with number_females = 0 But apart from that I can not come up with a solution that is shorter than yours. The table department seems to be irrelevant in this case, unless you need department names.

What is the basic functioning of group by in SQL?

What is the behaviour of group by?
I have two tables:
create table department
(
dep_id int primary key,
dep_id varchar(20),
dep_location varchar(20)
)
and
create table employees_dep
(
emp_id int primary key,
emp_name varchar(20),
job_name varchar(20),
manager_id int,
hire_date date,
salary decimal(10, 2),
commision decimal(7, 2),
dep_id int
foreign key references department(dep_id)
)
With data as:
insert into department values (1001, 'finance', 'sydney')
insert into department values (2001, 'audit', 'melbourne')
insert into department values (3001, 'marketing', 'perth')
insert into department values (4001, 'production', 'brisbane')
insert into employees_dep
values (68319, 'kayling', 'president', null, '11-18-1991', 6000, 0, 1001)
insert into employees_dep
values (66928, 'blaze', 'manager', 68319, '05-01-1991', 2750, 0, 3001)
insert into employees_dep
values (67832, 'clare', 'manager', 68319, '06-09-1991', 2550, 0, 1001)
insert into employees_dep
values (65646, 'jonas', 'manager', 68319, '04-02-1991', 2957, 0, 2001)
insert into employees_dep
values (67858, 'scarlet', 'analyst', 65646, '04-19-1991', 3100, 0, 2001)
insert into employees_dep
values (69062, 'frank', 'analyst', 65646, '12-03-1991', 3100, 0, 2001)
insert into employees_dep
values (63679, 'sandrine', 'clerk', 69062, '12-18-1991', 900, 0, 2001)
insert into employees_dep
values (64989, 'adelyn', 'salesman', 66928, '02-20-1991', 1700, 400, 3001)
insert into employees_dep
values (65271, 'wade', 'salesman', 66928, '02-22-1991', 1350, 600, 3001)
insert into employees_dep
values (66564, 'madden', 'salesman', 66928, '09-28-1991', 1350, 1500, 3001)
insert into employees_dep
values (68454, 'tucker', 'salesman', 66928, '09-08-1991', 1600, 0, 3001)
insert into employees_dep
values (68736, 'andres', 'clerk', 67858, '05-23-1997', 1200, 0, 2001)
insert into employees_dep
values (69000, 'julius', 'clerk', 66928, '12-03-1991', 1050, 0, 3001)
insert into employees_dep
values (69324, 'marker', 'clerk', 67832, '01-23-1992', 1400, 0, 1001)
The question: when I write a query as:
select
d.dep_name,
count(d.dep_name) as no_of_employees
from
employees_dep e, department d
group by
d.dep_name
The output is:
all the department names with no_of_employees as 14 in all the rows
Why is this so because the group by clause selects one data and make group of it so it should work as select the first department name and then group all the rows in employee table with same department id and then count the no of rows in each group
when i write query as -
select
d.dep_name,
count(d.dep_name) as no_of_employees
from
employees_dep e, department d
where
e.dep_id = d.dep_id
group by
d.dep_name
Then it returns the correct output with the correct number of occurrences of each department in the table.
Please explain this behaviour of group by....
Use inner join. hope this help
select d.dep_name,
count(d.dep_name) as no_of_employees
from employees_dep e
inner join department d on e.dep_id = d.dep_id
group by d.dep_name
You are using implicit join syntax and are creating a Cartesian Join (Cross Join) which means every possible combination of the 2 tables is then being counted. So if you have 14 departments every employee will look as if it is in 14 of them. Researching how to do joins in SQL and use explicit join syntax will help out. In this case INNER JOIN as others have also pointed out will be the key to correcting the issue.
SELECT
d.dep_name
,count(emp_id) as no_of_employees
FROM
department d
INNER JOIN employees_dep e
ON e.dep_id = d.dep_id
GROUP BY
d.dep_name
You much use a joining condition in your first query. Else it will do a cross join. Using proper joining condition will give you the proper output.
select d.dep_name,count(1) as no_of_employees
from employees_dep e join department d
On e.dep_id=d.dep_id
group by d.dep_name

Selecting data across mulitple tables in Oracle SQL

I am new to SQL and I am trying to lists all organizations by name in ascending order with the maximum salary across all employees who belong to the organization. I have the Schema Below. Can anyone offer any help? I am also trying to lists all employees by name and if the employee is a manager of at least one organization, provide a row in the results with the name
of each org he/she manages else null.
SELECT Org.name, MAX(Employee.salary) AS "Highest salary"
From Org, Employee
GROUP BY Org.name;
The above code gets me a list of all the Org Names with the global max salary, but I am looking for the max of each Org. I think I may need to use some joins but I am not very familiar.
CREATE TABLE Employee
(
employeeId numeric(9) not null,
name varchar2(100) unique,
salary numeric(9) not null,
CONSTRAINT employeeId_pk PRIMARY KEY (employeeId)
);
CREATE TABLE Org
(
orgId numeric(9) not null,
name varchar2(100) not null unique,
managerId numeric(9) not null,
CONSTRAINT orgId_pk PRIMARY KEY (orgId),
CONSTRAINT managerId_fk FOREIGN KEY (managerId)
REFERENCES Employee(employeeId)
);
CREATE TABLE EmployeeOrg
(
employeeId numeric(9) not null,
orgId numeric(9) not null,
CONSTRAINT employeeId_orgId_pk PRIMARY KEY (employeeId, orgId),
CONSTRAINT employeeId_fk FOREIGN KEY (employeeId)
REFERENCES Employee(employeeId),
CONSTRAINT orgId_fk FOREIGN KEY (orgId)
REFERENCES Org(orgId)
);
INSERT ALL
INTO Employee (employeeId, name, salary) VALUES (123, 'Jim', 123)
INTO Employee (employeeId, name, salary) VALUES (456, 'Bill', 1456)
INTO Employee (employeeId, name, salary) VALUES (789, 'Frank', 456)
INTO Employee (employeeId, name, salary) VALUES (987, 'Sara', 45668)
INTO Employee (employeeId, name, salary) VALUES (654, 'Liz', 4456)
INTO Employee (employeeId, name, salary) VALUES (321, 'Morgan', 4556)
SELECT * FROM dual;
INSERT ALL
INTO Org (orgId, name, managerId) VALUES (1, 'Sales', 123)
INTO Org (orgId, name, managerId) VALUES (2, 'HR', 789)
INTO Org (orgId, name, managerId) VALUES (3, 'E Suite', 987)
INTO Org (orgId, name, managerId) VALUES (4, 'Marketing', 654)
SELECT * FROM dual;
INSERT ALL
INTO EmployeeOrg (employeeId, orgId) VALUES (123, 1)
INTO EmployeeOrg (employeeId, orgId) VALUES (789, 2)
INTO EmployeeOrg (employeeId, orgId) VALUES (987, 3)
INTO EmployeeOrg (employeeId, orgId) VALUES (654, 4)
INTO EmployeeOrg (employeeId, orgId) VALUES (123, 4)
INTO EmployeeOrg (employeeId, orgId) VALUES (456, 1)
INTO EmployeeOrg (employeeId, orgId) VALUES (321, 2)
INTO EmployeeOrg (employeeId, orgId) VALUES (789, 4)
INTO EmployeeOrg (employeeId, orgId) VALUES (456, 2)
SELECT * FROM dual;
EDIT (from OP's comment)
The below code gets me a list of all the Org Names with the global max salary, but I am looking for the max of each Org. I think I may need to use some joins but I am not very familiar.
SELECT Org.name, MAX(Employee.salary) AS "Highest salary"
From Org, Employee
GROUP BY Org.name
select o.orgId, min(o.name) as orgName, max(e.salary) as maxSalary
from Org o
inner join EmployeeOrg eo on eo.orgId = o.orgId
inner join Employee e on e.employeeId = eo.employeeId
group by o.orgId
order by orgName;
select e.name as empName, o.name as orgName
from Employee e left outer join Org o on o.managerId = e.employeeId
order by empName, orgName;

SQL developer Query

QUESTION: Write a SQL SELECT statement to display the name and address of all departments (except the departments in Dallas) having maximum number of employees. Sort your output in ascending order by department name.
Creating Department Table
CREATE TABLE department
( DEPARTMENT_ID NUMBER(4) PRIMARY KEY,
DEPARTMENT_NAME VARCHAR2(20) NOT NULL UNIQUE,
ADDRESS VARCHAR2(20) NOT NULL);
Populating Department Table
INSERT INTO department VALUES(10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO department VALUES(20, 'RESEARCH', 'DALLAS');
INSERT INTO department VALUES(30, 'SALES', 'CHICAGO');
INSERT INTO department VALUES(40, 'IT', 'DALLAS');
INSERT INTO department VALUES(50, 'EXECUTIVE', 'NEW YORK');
INSERT INTO department VALUES(60, 'MARKETING', 'CHICAGO');
COMMIT;
Creating Employee Table
CREATE TABLE employee
( EMPLOYEE_ID NUMBER(4) PRIMARY KEY,
EMPLOYEE_NAME VARCHAR2(20) NOT NULL,
JOB VARCHAR2(50) NOT NULL,
MANAGER_ID NUMBER(4),
HIRE_DATE DATE NOT NULL,
SALARY NUMBER(9, 2) NOT NULL,
COMMISSION NUMBER(9, 2),
DEPARTMENT_ID NUMBER(4) REFERENCES department(DEPARTMENT_ID));
Populating Employee Table
INSERT INTO employee
VALUES(7839, 'KING', 'PRESIDENT', NULL, '20-NOV-01', 5000, NULL, 50);
INSERT INTO employee
VALUES(7596, 'JOST', 'VICE PRESIDENT', 7839, '04-MAY-01', 4500, NULL, 50);
INSERT INTO employee
VALUES(7603, 'CLARK', 'VICE PRESIDENT', 7839, '12-JUN-01', 4000, NULL, 50);
INSERT INTO employee
VALUES(7566, 'JONES', 'PUBLIC ACCOUNTANT', 7596, '05-APR-01', 3000, NULL, 10);
INSERT INTO employee
VALUES(7886, 'STEEL', 'PUBLIC ACCOUNTANT', 7566, '08-MAR-03', 2500, NULL, 10);
INSERT INTO employee
VALUES(7610, 'WILSON', 'ANALYST', 7596, '03-DEC-01', 3000, NULL, 20);
INSERT INTO employee
VALUES(7999, 'WOLFE', 'ANALYST', 7610, '15-FEB-02', 2500, NULL, 20);
INSERT INTO employee
VALUES(7944, 'LEE', 'ANALYST', 7610, '04-SEP-06', 2400, NULL, 20);
INSERT INTO employee
VALUES(7900, 'FISHER', 'SALESMAN', 7603, '06-DEC-01', 3000, 500, 30);
INSERT INTO employee
VALUES(7921, 'JACKSON', 'SALESMAN', 7900, '25-FEB-05', 2500, 400, 30);
INSERT INTO employee
VALUES(7952, 'LANCASTER', 'SALESMAN', 7900, '06-DEC-06', 2000, 150, 30);
INSERT INTO employee
VALUES(7910, 'SMITH', 'DATABASE ADMINISTRATOR', 7596, '20-DEC-01', 2900, NULL, 40);
INSERT INTO employee
VALUES(7788, 'SCOTT', 'PROGRAMMER', 7910, '15-JAN-03', 2500, NULL, 40);
INSERT INTO employee
VALUES(7876, 'ADAMS', 'PROGRAMMER', 7910, '15-JAN-03', 2000, NULL, 40);
INSERT INTO employee
VALUES(7934, 'MILLER','PROGRAMMER', 7876, '25-JAN-02', 1000, NULL, 40);
INSERT INTO employee
VALUES(8000, 'BREWSTER', 'TBA', NULL, '22-AUG-13', 2500, NULL, NULL);
COMMIT;
The Query That i wrote is below and it works perfectly in finding the maximum number of employees in DALLAS department but I want to eliminate DALLAS and find the other department which has the MAXIMUM number of employee's working in it which is by the data are (CHICAGO and NEW YORK). Can anyone please help me out?
SELECT d.department_id, d.department_name, COUNT(*)
FROM department d
INNER JOIN employee e
ON d.department_id = e.department_id
GROUP BY d.department_id, d.department_name
HAVING COUNT(*) = (SELECT MAX(COUNT(*))
FROM employee
GROUP BY department_id)
ORDER BY department_id;
Using your query:
SELECT d.department_id, d.department_name, COUNT(*)
FROM department d
INNER JOIN employee e
ON d.deptartment_id = e.department_id
where d.address != 'DALLAS'
GROUP BY d.department_id, d.department_name
HAVING COUNT(*) = (SELECT MAX(COUNT(*))
FROM employee
where department_id not in (select department_id from department where address = 'DALLAS')
GROUP BY department_id)
ORDER BY department_id;
;
You can use a rank analytic function:
select *
from (
select department_id, department_name, rank() over (order by cnt desc) rnk
from(
SELECT d.department_id, d.department_name, COUNT(*) cnt
FROM department d
INNER JOIN employee e
ON d.department_id = e.department_id
GROUP BY d.department_id, d.department_name
)
)
where rnk = 2 --here you may change to what position you want
;

SQL Help(Date Functions)

I need help on SQL Queries.
TABLE:
Create Table Employees
( employee_id number(3) Primary Key,
first_name varchar2(10),
last_name varchar2(10),
dept_code varchar2(3),
hire_date date,
credit_limit number(4,2),
phone_ext varchar2(4),
manager_id number(3)
);
Entries:
insert into Employees values (201, 'Susan', 'Brown', 'Exe', To_Date('01-Jun-1998','DD-Mon-YYYY'), 30, '3484', null);
insert into Employees values (202, 'Jim', 'Kern', 'Sal', To_Date('16-Aug-1999','DD-Mon-YYYY'), 25, '8722', 201);
insert into Employees values (203, 'Martha', 'Woods', 'Shp', To_Date('02-Feb-2004','DD-Mon-YYYY'), 25, '7591', 201);
insert into Employees values (204, 'Ellen', 'Owens', 'Sal', To_Date('01-Jul-2003','DD-Mon-YYYY'), 15, '6830', 202);
I need a query to List all the employees, their hire dates and the number of days each person will have worked for the company as of January 1, 2007.
You can use YEAR() on a date field:
SELECT * FROM Employees WHERE YEAR(hire_date)='2003'
if it doesn't work, you can use EXTRACT():
SELECT * FROM Employees WHERE EXTRACT(YEAR FROM hire_date)='2003'
and, as Alan Hadsell rightly commented:
SELECT COUNT(*) FROM Employees WHERE EXTRACT(YEAR FROM hire_date)='2003'