Display dummy row as group by clause heading in Oracle - sql

I have 3 tables say company, department and employee. Now I want to find out all the employees who works in company A under department D and want to display data as below.
There is parent key relation between all this tables
**TABLE COMPANY**
COMPANY_NAME COMPANY ID
C1 COMP1
C2 COMP2
C3 COMP3
**TABLE DEPARTMENT**
DEPARTMENT_NAME COMPANY_NAME
D1 C1
D2 C1
D3 C2
**TABLE EMPLOYEE**
EMPLOYEE_ID DEPARTMENT_NAME
E1 D1
E2 D1
E3 D1
E4 D2
E5 D2
Company -- > Department --- > Employee.
I also want to display entity against each column as dummy column.
ENTITY COMPANY_NAME DEPARTMENT_NAME EMPLOYEE_ID
COMPANY C1 - -
DEPARTMENT C1 D1
EMPLOYEE C1 D1 E1
EMPLOYEE C1 D1 E2
EMPLOYEE C1 D1 E3
DEPARTMENT C1 D2 -
EMPLOYEE C1 D2 E4
EMPLOYEE C1 D2 E5 ``
I Have tried this with group by, but with group by I get data as vertical tree like structure. but what i want is there should be heading like company or department and under that employees under that department should display. Is there are possible way we can do this in sql or plsql. ?
for left outer join
ENTITY COMPANY_NAME DEPARTMENT_NAME EMPLOYEE_ID
COMPANY C1 - -
DEPARTMENT C1 D1
EMPLOYEE C1 D1 E1
EMPLOYEE C1 D1 E2
EMPLOYEE C1 D1 E3
DEPARTMENT C1 D2 -
EMPLOYEE C1 D2 E4
EMPLOYEE C1 D2 E5
COMPANY C2 - -
DEPARTMENT C2 D3 -
COMPANY C3 - -

You can do this using aggregation -- and grouping sets. This looks like:
select (case when grouping(employee_id) = 0 then 'EMPLOYEE'
when grouping(department_name) = 0 then 'DEPARTMENT'
else 'COMPANY'
end) as entity,
company_name, department_name, e.employee_id
from company c join
department d
using (company_name) join
employee e
using (department_name)
group by grouping sets ( (company_name, department_name, e.employee_id), (company_name, department_name), (company_name) )
order by company_name, department_name nulls first, employee_id nulls first;
Here is a db<>fiddle.

You can use UNION ALL as follows:
SELECT COMPANY_NAME, NULL AS DEPARTMENT_NAME, NULL AS EMPLOYEE_ID
FROM COMPANY C
WHERE EXISTS (SELECT 1 FROM EMPLOYEE E JOIN DEPARTMENT D USING (DEPARTMENT_NAME)
WHERE C.COMPANY_NAME = D.COMPANY_NAME)
UNION ALL
SELECT COMPANY_NAME, DEPARTMENT_NAME, NULL AS EMPLOYEE_ID
FROM COMAPNY C JOIN DEPARTMENT D USING (COMPANY_NAME)
WHERE EXISTS (SELECT 1 FROM EMPLOYEE E
WHERE E.DEPARTMENT_NAME = D.DEPARTMENT_NAME)
UNION ALL
SELECT COMPANY_NAME, DEPARTMENT_NAME, EMPLOYEE_ID
FROM EMPLOYEE JOIN DEPARTMENT USING (DEPARTMENT_NAME)
ORDER BY COMPANY_NAME,
DEPARTMENT_NAME NULLS FIRST,
EMPLOYEE_ID NULLS FIRST;

Related

list of Employee having 2 products

Can someone help here.
I have table employee. I want to find out list of employees having 2 products(P1,P2).
Emp_id Prd_id
E1 P1
E1 P2
E2 P1
E2 P2
E2 P3
E3 P1
E3 P3
E4 P1
E4 P2
So, I want output as
Emp_id
E1
E4
SELECT emp_id
FROM employee
GROUP BY emp_id
HAVING COUNT(CASE WHEN prd_id 'p1' THEN 1 END) > 0 -- p1 exists
AND COUNT(CASE WHEN prd_id 'p2' THEN 1 END) > 0 -- p2 exists
AND COUNT(CASE WHEN prd_id NOT IN ('p1', 'p2') THEN 1 END) = 0 -- but not other
Easier to extend to a larger number of products:
SELECT emp_id
FROM
( -- get a unique list first
SELECT DISTINCT emp_id, prd_id
FROM employee
) AS dt
GROUP BY emp_id
HAVING SUM(CASE WHEN prd_id IN ('p1', 'p2') THEN 1 ELSE -1 END) = 2
If the requirement is to find employees with any two products, you could use a having condition to count them:
SELECT emp_id
FROM employees
GROUP BY emp_id
HAVING COUNT(*) = 2
If those products must be p1 and p2, you could add another condition on that:
SELECT emp_id
FROM employees
GROUP BY emp_id
HAVING COUNT(*) = 2 AND
COUNT(CASE WHEN prd_id IN ('p1', 'p2') THEN 1 END) = 2

show dummy row as group by heading for left outer join

I have 3 tables say company, department and employee. Now I want to find out all the employees who works in company A under department D and want to display data for inner as well as left outer join to see any department that does not have any employee and company which does not have any department.
There is parent key relation between all this tables
**TABLE COMPANY**
COMPANY_NAME COMPANY ID
C1 COMP1
C2 COMP2
C3 COMP3
**TABLE DEPARTMENT**
DEPARTMENT_NAME COMPANY_NAME
D1 C1
D2 C1
D3 C2
**TABLE EMPLOYEE**
EMPLOYEE_ID DEPARTMENT_NAME
E1 D1
E2 D1
E3 D1
E4 D2
E5 D2
Company -- > Department --- > Employee.
I also want to display entity against each column as dummy column.
ENTITY COMPANY_NAME DEPARTMENT_NAME EMPLOYEE_ID
COMPANY C1 - -
DEPARTMENT C1 D1
EMPLOYEE C1 D1 E1
EMPLOYEE C1 D1 E2
EMPLOYEE C1 D1 E3
DEPARTMENT C1 D2 -
EMPLOYEE C1 D2 E4
EMPLOYEE C1 D2 E5
COMPANY C2 - -
DEPARTMENT C2 D3 -
COMPANY C3 - -
You can use the SET operator UNION ALL as follows:
SELECT 'COMPANY' AS ENTITY,
COMPANY_NAME,
'-' AS DEPARTMENT_NAME,
'-' AS EMPLOYEE_ID
FROM COMPANY C
UNION ALL
SELECT 'DEPARTMENT' AS ENTITY,
C.COMPANY_NAME,
D.DEPARTMENT_NAME,
'-' AS EMPLOYEE_ID
FROM DEPARTMENT D
JOIN COMPANY C ON C.COMPANY_ID = D.COMPANY_ID
UNION ALL
SELECT 'EMPLOYEE' AS ENTITY,
C.COMPANY_NAME,
D.DEPARTMENT_NAME,
E.EMPLOYEE_ID
FROM DEPARTMENT D
JOIN COMPANY C ON C.COMPANY_ID = D.COMPANY_ID
JOIN EMPLOYEE E ON E.DEPARTMENT_NAME = D.DEPARTMENT_NAME
ORDER BY COMPANY_NAME,
CASE WHEN DEPARTMENT_NAME = '-' THEN 1 ELSE 2 END,
DEPARTMENT_NAME,
CASE WHEN EMPLOYEE_ID = '-' THEN 1 ELSE 2 END,
EMPLOYEE_ID
Please try this:
select
case entity_disp
when 1 then 'COMPANY'
when 2 then 'DEPARTMENT'
when 3 then 'EMPLOYEE'
end as entity,
company_name,
department_name,
employee_id
from
(select
c.company_name,
d.department_name,
e.employee_id,
1 + decode(d.department_name, null, 0, 1) + decode(e.employee_id, null, 0, 1) as entity_disp
from
company c
left outer join department d on (d.company_name = c.company_name)
left outer join employee e on (e.department_name = d.department_name)
) c
order by c.entity_disp
Take into consideration that according yor tabel model expample it looks like that Company and Department tabels are joined based on company_name. Also Department and Employee tables are joined based on Department_name.
This is how select is implemented. If needed - rework joins with proper relational columns.

How to display multiple hierarchical tree structure in BigQuery

I am working on the tree hierarchy of supervisors and their supervised employees. The difficulty is that some supervisors are employees supervised by other supervisors, and there are lots of it.
For SQL queries I acquired from class, only about simple self-joins, which might be only like two levels: A is supervised by B, and that's it.
But the issue from the real world is far more complicated. There are multiple levels, and I am not sure about the exact number. For example, A is supervised by B, and B is supervised by C, and C is supervised by D, etc.
I assume there are only like 5 or more levels for supervision. The raw data might be like this:
Employee Supervisor
A B
C B
D B
B V
E V
F E
G V
V (Blank which indicates no boss)
H A
The codes provided by some BigQuery expert is as below:
#standardSQL
SELECT t.Supervisor,
IF(t.Supervisor = t5.Supervisor,
STRUCT(Employee2 AS Employee1, NULL AS Employee2),
STRUCT(t5.Supervisor AS Employee1, Employee2 AS Employee2)
).*
FROM (
SELECT t1.Employee Supervisor,
COALESCE(t4.Employee, t3.Employee, t2.Employee) Employee2
FROM `project.dataset.table` t1
LEFT JOIN `project.dataset.table` t2 ON t2.Supervisor = t1.Employee
LEFT JOIN `project.dataset.table` t3 ON t3.Supervisor = t2.Employee
LEFT JOIN `project.dataset.table` t4 ON t4.Supervisor = t3.Employee
WHERE t1.Supervisor IS NULL
) t
LEFT JOIN `project.dataset.table` t5 ON t5.Employee = t.Employee2
and the result turned to be like this:
Row Supervisor Employee1 Employee2
1 V B A
2 V B C
3 V B D
4 V E F
5 V G null
But we want is :
Row Supervisor Employee1 Employee2 Employee3
1 V B A H
2 V B C Null
3 V B D Null
4 V E F Null
5 V G null Null
Then how to change the codes if I would like to have more levels of hierarchies? which means if I would like to add employee3, or 4, how can I edit it? Thanks!
Below is for BigQuery Standard SQL
#standardSQL
WITH e0 AS (
SELECT Employee AS Supervisor FROM `project.dataset.table` WHERE Supervisor IS NULL
), e1 AS (
SELECT e.Supervisor, Employee AS Employee1
FROM e0 e LEFT JOIN `project.dataset.table` t ON t.Supervisor = e.Supervisor
), e2 AS (
SELECT e.Supervisor, Employee1, Employee AS Employee2
FROM e1 e LEFT JOIN `project.dataset.table` t ON t.Supervisor = e.Employee1
), e3 AS (
SELECT e.Supervisor, Employee1, Employee2, Employee AS Employee3
FROM e2 e LEFT JOIN `project.dataset.table` t ON t.Supervisor = e.Employee2
)
SELECT * FROM e3
if to apply to sample data from your question - result/output is
Row Supervisor Employee1 Employee2 Employee3
1 V B A H
2 V B C null
3 V B D null
4 V E F null
5 V G null null
You can easily extend above adding more levels like below (replacing and with respective numbers like 4, 5, 6, 7 etc.) Obviously up to reasonable extend
e<N> AS (
SELECT e.Supervisor, Employee1, Employee2, Employee3, ... , Employee AS Employee<N>
FROM e<N-1> e LEFT JOIN `project.dataset.table` t ON t.Supervisor = e.Employee<N-1>
)
SELECT * FROM e<N>
for example
#standardSQL
WITH e0 AS (
SELECT Employee AS Supervisor FROM `project.dataset.table` WHERE Supervisor IS NULL
), e1 AS (
SELECT e.Supervisor, Employee AS Employee1
FROM e0 e LEFT JOIN `project.dataset.table` t ON t.Supervisor = e.Supervisor
), e2 AS (
SELECT e.Supervisor, Employee1, Employee AS Employee2
FROM e1 e LEFT JOIN `project.dataset.table` t ON t.Supervisor = e.Employee1
), e3 AS (
SELECT e.Supervisor, Employee1, Employee2, Employee AS Employee3
FROM e2 e LEFT JOIN `project.dataset.table` t ON t.Supervisor = e.Employee2
), e4 AS (
SELECT e.Supervisor, Employee1, Employee2, Employee3, Employee AS Employee4
FROM e3 e LEFT JOIN `project.dataset.table` t ON t.Supervisor = e.Employee3
), e5 AS (
SELECT e.Supervisor, Employee1, Employee2, Employee3, Employee4, Employee AS Employee5
FROM e4 e LEFT JOIN `project.dataset.table` t ON t.Supervisor = e.Employee4
)
SELECT * FROM e5

SQL - GROUP BY and COUNT

I have a table with Column - D and E.
I want to get D, Distinct E in each D, Count of total number of entry for each D. How to write SQL for this ?
Data:
D | E
-----
1 | K
1 | K
1 | A
2 | S
2 | S
2 | S
2 | S
Desired o/p:
D | E | Total_E_in_D
----------------------
1 | K | 3
1 | A | 3
2 | S | 4
SELECT D,E,Count(E in each D)
FROM table
GROUP BY D,E.
Last column should give me the total number of entries for each D.
The specific answer to the question is:
select dept, count(*) as numemployees, count(distinct emp) as numDistinctEmployees
from d1
group by dept;
This just seems quite unusual, because the it assumes that employees would be in the same department more than once.
EDIT:
Strange data format, but just use aggregation with analytic functions:
select dept, emp, sum(count(*)) over (partition by dept) as numEmployees
from d1
group by dept, emp;
You can group on the department and the employee, and join in a query where you group on the department to count the employees:
select
e.Dept,
e.Emp
d.EmpCount
from
table e
inner join (
select
Dept,
count(distinct Emp) as EmpCount
from
table
group by
Dept
) d on d.Dept = e.Dept
group by
e.Dept, e.Emp
You could also use a subquery to count the employees:
select
e.Dept,
e.Emp,
(
select
count(distinct Emp)
from
table d
where
d.Dept = e.Dept
) as EmpCount
from
table e
group by
e.Dept, e.Emp
how's this?
select dept, emp, (select count(*) from table t2 where t2.dept = t1.dept) noEmps
from table t1

Oracle 10 g -SQL

How to find top 2 salaries in each department in emp table?
Emp Table
-----------
Row_id Salary Dept
R1 2000 D1
R2 3000 D1
R3 4000 D1
R4 5000 D1
R5 2000 D2
R6 3000 D2
R7 4000 D2
R8 5000 D2
select
row_id,salary,dept
from
(
select
row_number() over (partition by dept order by salary desc) as sno,
row_id,salary,dept
from emp
) t
where sno<=2
please try this
select T1.Dept,T2.Salary
from Emp_Table T1 join Emp_Table T2
on T1.Dept=T2.Dept
and T1.Salary>=T2.Salary
group by T1.Dept,T2.Salary
having COUNT(*) <=2