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.
Related
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
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;
I have the following query to get the primary (main) and secondary function for each employee :
with
employeeScopeFunctions as (
select e.employeeId,
es.FunctionId,
ef.Label,
c.CompanyName,
realOrder = row_number() over(
partition by e.employeeId
order by isnull(es.sortOrder, 9999)
)
from employee e
LEFT JOIN employee_scope es on es.employeeId = e.employeeId
LEFT JOIN employee_function ef on es.FunctionId = ef.FunctionId
LEFT JOIN Company c ON es.CompanyId = c.ID
WHERE e.EmployeeId=54
)
select *,
primacy = iif(realOrder = 1, 'main', 'secondary')
from employeeScopeFunctions
For the EmployeeId=54 the result is like below :
EmployeeId FunctionId Label CompanyName realOrder Primacy
54 273 Group Chief Executive Officer C1 1 primary
54 273 Group Chief Executive Officer C2 2 secondary
54 273 Group Chief Executive Officer X5 3 secondary
54 897 Group Regional Chief Executive Officer X6 4 secondary
54 897 Group Regional Chief Executive Officer F6 5 secondary
54 39 Director VY 6 secondary
54 39 Director G7 7 secondary
What I want to get is regroup all the companies for a specific function and get three levels of primacy :
EmployeeId FunctionId Label CompanyName Primacy
54 273 Group Chief Executive Officer C1,C2,X5 primary
54 897 Group Regional Chief Executive Officer X6,F6 secondary
54 39 Director VY,G7 tertiary
If I followed you correctly, you could keep your existing CTE and turn on aggregation in the main query. ROW_NUMBER() can be used to rank the records by increasing realOrder.
This should work in SQL-Server:
WITH employeeScopeFunctions as (
SELECT
e.employeeId,
es.FunctionId,
ef.Label,
c.CompanyName,
realOrder = row_number() over(partition by e.employeeId order by isnull(es.sortOrder, 9999))
FROM
employee e
LEFT JOIN employee_scope es ON es.employeeId = e.employeeId
LEFT JOIN employee_function ef ON es.FunctionId = ef.FunctionId
LEFT JOIN company c ON es.CompanyId = c.ID
WHERE e.EmployeeId=54
)
SELECT
employeeId,
FunctionId,
Label,
CompanyName = STRING_AGG(CompanyName, ',') WITHIN GROUP (ORDER BY realOrder),
Primacy = CASE ROW_NUMBER() OVER(ORDER BY MIN(realOrder))
WHEN 1 THEN 'primary'
WHEN 2 THEN 'secondary'
WHEN 3 THEN 'tertiary'
END
FROM employeeScopeFunctions
GROUP BY
employeeId,
FunctionId,
Label
Alternative solution with an additional level of nesting to avoid nesting window function and aggregation:
WITH employeeScopeFunctions as (
SELECT
e.employeeId,
es.FunctionId,
ef.Label,
c.CompanyName,
realOrder = row_number() over(partition by e.employeeId order by isnull(es.sortOrder, 9999))
FROM
employee e
LEFT JOIN employee_scope es ON es.employeeId = e.employeeId
LEFT JOIN employee_function ef ON es.FunctionId = ef.FunctionId
LEFT JOIN company c ON es.CompanyId = c.ID
WHERE e.EmployeeId=54
)
SELECT
employeeId,
FunctionId,
Label,
CompanyName,
Primacy = CASE ROW_NUMBER() OVER(ORDER BY minRealOrder)
WHEN 1 THEN 'primary'
WHEN 2 THEN 'secondary'
WHEN 3 THEN 'tertiary'
END
FROM (
SELECT
employeeId,
FunctionId,
Label,
CompanyName = STRING_AGG(CompanyName, ',') WITHIN GROUP (ORDER BY realOrder),
minRealOrder = MIN(realOrder)
FROM employeeScopeFunctions
GROUP BY
employeeId,
FunctionId,
Label
) x
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
We have 3 tables in Oracle 11g, need to left join them and return the data in single row different columns with count of the join, Is there any way We can acheive the same.
Example:
Table1: (Employee_Data)
Table2: (Employee_Address)
Table3: (Employee_Role)
Expected Result:
Mack has 2 addresses and 2 roles so Emp_Addr_Count is 2, Emp_Role_Count is 2 and the related data is in same row different column.
Kindly note that EMP_ID is unique in Employee_Data table and Employee_Address and Employee_Role could be multiple or zero for a Employee.
Thanks in Advance.
Try this:
SELECT E.Emp_Id
,E.Emp_Name
,E.Emp_Age
,NVL(MAX(EA.RN),0)Addr_Count
,NVL(MAX(CASE WHEN EA.RN = 1 THEN EA.Emp_Address END),' ')Emp_Address_1
,NVL(MAX(CASE WHEN EA.RN = 1 THEN EA.Emp_City END),' ')Emp_City_1
,NVL(MAX(CASE WHEN EA.RN = 2 THEN EA.Emp_Address END),' ')Emp_Address_2
,NVL(MAX(CASE WHEN EA.RN = 2 THEN EA.Emp_City END),' ')Emp_City_2
,NVL(MAX(ER.RN1),0)Role_Count
,NVL(MAX(CASE WHEN ER.RN1 = 1 THEN ER.Emp_task END),' ')Emp_task_1
,NVL(MAX(CASE WHEN ER.RN1 = 2 THEN ER.Emp_task END),' ')Emp_task_2 FROM Employee_Data E JOIN(
SELECT Emp_Id
,ROW_NUMBER() OVER(PARTITION BY Emp_Id ORDER BY Emp_City desc) RN
,Emp_City
,Emp_Address
FROM Employee_Address
)EA ON EA.Emp_Id = E.Emp_Id left JOIN(
SELECT Emp_Id
,ROW_NUMBER() OVER(PARTITION BY Emp_Id ORDER BY Emp_Task) RN1
,Emp_task
FROM Employee_Role
)ER ON ER.Emp_Id = E.Emp_Id GROUP BY E.Emp_Id,E.Emp_Name,E.Emp_Age
Output:
EMP_ID EMP_NAME EMP_AGE ADDR_COUNT EMP_ADDRESS_1 EMP_CITY_1 EMP_ADDRESS_2 EMP_CITY_2 ROLE_COUNT EMP_TASK_1 EMP_TASK_2
1 MACK 45 2 HOME PARADISE MUM TINDER ONCLAVE DEL 2 Manage Task Resource Manage
2 JACK 30 1 BLUE PLAZA MUM 1 Code
3 ANGEL 27 1 HOME PARADISE MUM 0
You can join them as in the following statement :
WITH t AS
(
SELECT d.*, a.emp_address, a.emp_city, r.emp_task
FROM employee_data d
JOIN employee_address a on ( d.emp_id = a.emp_id )
FULL OUTER JOIN employee_role r on ( d.emp_id = r.emp_id )
)
SELECT emp_id, emp_name, emp_age, count(distinct emp_address) emp_addr_count,
min(emp_address) emp_address_1, max(emp_city) emp_city_1,
decode(min(emp_address),max(emp_address),null,max(emp_address)) emp_address_2,
decode(min(emp_city),max(emp_city),null,min(emp_city)) emp_city_2,
count(distinct emp_task) emp_role_count, min(emp_task) emp_task_1,
decode(min(emp_task),max(emp_task),null,max(emp_task)) emp_task_2
FROM t
GROUP BY emp_id, emp_name, emp_age
ORDER BY emp_id;
SQL Fiddle Demo