CTE to replace JOIN - sql

Can I use CTE instead of the my code here ? Here are the two tables and my code .
tbl1
D_ID department employee name manager name
112 d01 john d Peter k
113 d01 Emily f kevin s
tbl2
Emp_id employee name D_ID
100 john d 112
200 peter k 112
800 Emily f 113
500 kevin s 113
My code below , what I did is I joined tbl1 with tbl2 on D_ID and employee name and then filter out the records where employee's emp_id > manager's emp_id .
DECLARE #level nvarchar(MAX) =
(
select X.D_ID ,x.employee_NAME, x.emp_ID as employee_id,
y.manager_name ,y.emp_id as manager_id
) + ' '
from (
select distinct b.d_id , a.emp_id as employee_id
from tbl1 a , tbl2 b
where a.d_id=b.d_id and a.employee_NAME=b.employee_NAME
) x ,
(
select distinct b.d_id , a.emp_id as manager_id
from tbl1 a , tbl2 b
where a.d_id=b.d_id and a.employee_NAME=b.manager_NAME
) Y
where x.department=y.department and x.employee_id>=y.manager_id
FOR XML PATH('')
)
IF #level IS NOT NULL
BEGIN
RAISERROR(' employee ID>manager_id: %s',16, 1, #level)
with log;
END;
DESIRED OUTPUT is below as Emily f's employee id is > than her manager's ID .
D_ID employee_NAME employee_id manager_name manager_id
113 Emily f 800 kevin s 500

I think you just need some joins:
select t1.d_id, t1.employee_name, te.emp_id,
t1.employee_name as manager_name, tm.emp_id as manager_id
from tbl1 t1 join
tbl2 te
on t1.employee_name = te.employee_name join
tbl2 tm
on t1.manager_name = tm.employee_name
where te.emp_id > tm.emp_id;
It is quite curious that you are using the names to connect the two tables. Normally, you would use the employee id for this purpose and look up the name using the id.

Related

Update using joins by finding the previous value in sql

I have two tables and I have to update the address field in the emp table by looking up in the emphistory table with previous value i.e USA for employee John
Table emp
EId ename sal Address AccountId
-------------------------------
101 John 100 U X12
102 Peter 500 Null X13
Table emphistory
emphisid EId AccountId Address Date (use row_number to find the second record for that eid and accountid)
-----------------------------------------------------
1 101 X12 U 11-01-2020 09:45:00
2 102 X13 Null 11-01-2020 09:46:00
3. 101 X12 USA 11-01-2020 09:30:00
I have to join the tables with account id and eid.
This works in Postgresql & Sql Server
UPDATE emp
SET Address = hist.Address
FROM (
SELECT h.EId, h.AccountId, h.Address
, ROW_NUMBER() OVER (PARTITION BY h.EId, h.AccountId
ORDER BY h.Date DESC) AS Rn
FROM emphistory h
JOIN emp e
ON e.EId = h.EId
AND e.AccountId = h.AccountId
WHERE h.Address IS NOT NULL
) hist
WHERE emp.EId = hist.EId
AND hist.Rn = 2

SQL Server - Self Join

I have a table as follows
EmployeeID Name ManagerID
2 David 3
3 Roger NULL
4 Marry 2
5 Joseph 2
7 Ben 2
Here Roger is Top Manager
Mike & David are Managers
And rest all are employees
I am looking for output like this:
EmployeeName ManagerName TopManager
Marry David Roger
Joseph David Roger
Ben David Roger
NULL David Roger
I tried using Self Join like:
SELECT e1.Name EmployeeName, ISNULL(e2.name, 'Top Manager') AS ManagerName
FROM Employee e1
LEFT JOIN Employee e2
ON e1.ManagerID = e2.EmployeeID
but it is not giving the output I am looking for.
If you can have different top managers, then a recursive CTE is needed:
with cte as (
select employeeid, name, name as topmanager
from Employee
where managerid is null
union all
select t.employeeid, t.name, cte.topmanager
from Employee t join
cte
on t.managerid = cte.employeeid
)
select *
from cte;
If there is only one top manager, then:
select e.*, topm.name as topmanager
from employee e cross join
(select e2.* from employee e2 where e2.managerid is null) as topm
I think you have to do self join twice to get the desired output.
I created the query in this way and got the output which you have mentioned. Please note that I did not include the last row which has null value, and rest the same as it is.
Query:
create table Employees (EmployeeID int, Name varchar(10), ManagerID int)
Insert into Employees values
(2, 'David' , 3 )
,(3, 'Roger' , NULL)
,(4, 'Marry' , 2 )
,(5, 'Joseph' , 2 )
,(7, 'Ben' , 2 )
select e.name as EmployeeName, e1.name ManagerName, e2.Name TopManager
from Employees e
left join Employees e1 on e.ManagerID = e1.employeeid
left join Employees e2 on e1.ManagerID = e2.EmployeeID
where e.ManagerID is not null and e1.ManagerID is not null
Where condition was given to restrict the manager names in Employee column.
Output:
EmployeeName ManagerName TopManager
Marry David Roger
Joseph David Roger
Ben David Roger

Select highest value over multiple tables

I have the following tables
Table Name : tHREmployee
EmployeID# Employee DepartmentID DesignationID DOB BasicPay
101 Ajith 101 102 10/Feb/1982 10000
102 Aarathy NULL 101 15/Mar/1981 15000
103 Aruna 102 NULL 20/Sep/1980 5000
104 Ambily 101 NULL 20/Sep/1980 5000
105 Anjaly NULL 101 20/Sep/1980 10000
106 Babitha 103 NULL 20/Sep/1981 20000
Table Name : tHRDepartment
DepartmentID# Code Department
101 500 Production
102 501 HR
103 502 Finance
105 503 Marketing
Table Name : tHRDesignation
DesignationID# Designation
101 Executive
102 Manager
How can I display employee details (Employee, Department, Designation, basicPay) for those employees who have highest basic pay for each department in sql?
In Oracle, this should help you
WITH CTE AS
(
SELECT DepartmentID , MAX(BasicPay) MAXPAY FROM tHREmployee
GROUP BY DepartmentID
)
SELECT E.EmployeID EMPid, E.Employee EMP_NAME , DPT.Department DPT_NAME,
DSG.Designation DSG_NAME, BASICPAY
FROM CTE, tHREmployee E,tHRDepartment DPT, Designation DSG
WHERE
E.BASICPAY = MAXPAY
AND E.DepartmentID = CTE.DepartmentID
AND E.DepartmentID = DPT.DepartmentID
AND E.DesignationID = DSG.DesignationID
In other DBs, something similar to this would help you:
SELECT E.EmployeID EMPid, E.Employee EMP_NAME , DPT.Department DPT_NAME,
DSG.Designation DSG_NAME, BASICPAY
FROM tHREmployee E,tHRDepartment DPT, Designation DSG
WHERE
E.DepartmentID = CTE.DepartmentID
AND E.DepartmentID = DPT.DepartmentID
AND E.DesignationID = DSG.DesignationID
AND E.BASICPAY IN
( SELECT MAX(EE.BASICPAY) FROM tHREmployee EE GROUP BY DPT.DepartmentID )
Select A.Employee,B.Department ,c.Designation,a.BAsicPay from Employee A inner join Department B on A.Department=B.DepartmentID left join Designation C on A.designationID=C.DesignationID inner join (Select DepartmentID,max(BasicPay) as BasicPay from Employee group by DepartmentID) as s2
on s2.DepartmentID=A.DepartmentID and A.BAsicPay=s2.BasicPAy

Return multiple values in one column

I have two tables
Employee:
Empid Ename Eage Eadd Ephone
1 x 23 b 677
2 y 24 h 809
3 z 34 u 799
Department:
Did fkEmpid dname ddescription
123 1 test test
234 1 test1 test1
667 2 hello hello
Finally I want something like this
Ename Eage Eadd Ephone dname
x 23 b 677 test,test1
y 24 h 809 hello
z 34 u 799 null
Please help me with the SQL
It certainly would be nice to know the target RDBMS. But this question is asked so often so let's try and list'em all (at least popular ones) side by side.
For SQL Server:
SELECT e.Ename, e.Eage, e.Eadd, e.Ephone, d.dname
FROM Employee e LEFT JOIN
(
SELECT fkEmpid,
STUFF((SELECT ',' + dname
FROM Department
WHERE fkEmpid = t.fkEmpid
FOR XML PATH('')) , 1 , 1 , '' ) dname
FROM Department t
GROUP BY fkEmpid
) d
ON e.Empid = d.fkEmpid
Here is SQLFiddle demo
For Mysql, SQLite, HSQLDB 2.X:
SELECT e.Ename, e.Eage, e.Eadd, e.Ephone, d.dname
FROM Employee e LEFT JOIN
(
SELECT fkEmpid,
GROUP_CONCAT(dname) dname
FROM Department t
GROUP BY fkEmpid
) d
ON e.Empid = d.fkEmpid
Here is SQLFiddle demo (MySql)
Here is SQLFiddle demo (SQLite)
For Oracle 11g:
SELECT e.Ename, e.Eage, e.Eadd, e.Ephone, d.dname
FROM Employee e LEFT JOIN
(
SELECT fkEmpid,
LISTAGG (dname, ',') WITHIN GROUP (ORDER BY dname) dname
FROM Department t
GROUP BY fkEmpid
) d
ON e.Empid = d.fkEmpid
Here is SQLFiddle demo
For PostgreSQL 9.X:
SELECT e.Ename, e.Eage, e.Eadd, e.Ephone, d.dname
FROM Employee e LEFT JOIN
(
SELECT fkEmpid,
string_agg(dname, ',') dname
FROM Department t
GROUP BY fkEmpid
) d
ON e.Empid = d.fkEmpid
Here is SQLFiddle demo
Output in all cases:
| ENAME | EAGE | EADD | EPHONE | DNAME |
---------------------------------------------
| x | 23 | b | 677 | test,test1 |
| y | 24 | h | 809 | hello |
| z | 34 | u | 799 | (null) |
Considering RDBMS as SQL SERVER 2008
select E.Ename,E.Eage,E.Eadd,E.Ephone,D.dname
into Table1
from Employee E
left join Deparment D on E.Empid=D.fkEmpid
select t1.[Ename], t1.[Eage], t1.[Eadd], t1.[Ephone],
STUFF((
SELECT ', ' + t2.dname
FROM Table1 t2
WHERE t2.Ename = t1.Ename
AND t2.Eage=t1.Eage
AND t2.Eadd=t1.Eadd
AND t2.Ephone=t1.Ephone
FOR XML PATH (''))
,1,2,'') AS Names
FROM Table1 t1
GROUP BY t1.Ename,t1.[Eage], t1.[Eadd], t1.[Ephone];
SQL FIDDLE

Get all employee who directly or indirectly reports to an employee, with hierarchy level no

I have a Employee table like
emp_id bigint,
reports_to bigint,
emp_name varchar(20),
Constraint [PK_Emp] Primary key (emp_id),
Constraint [FK_Emp] Foreign key (reports_to) references [MSS].[dbo].[Emp]([emp_id])
emp_id reports_to emp_name
------ ------ --------------
1 null Sumanta
2 1 Arpita
3 null Pradip
4 1 Sujon
5 2 Arpan
6 5 Jayanti
I want to get all the employees that directly or indirectly reports to Sumanta or emp_id(1), and with hierarchy level, like this:
emp_id hierarchy_level emp_name
------ --------------- ----------
2 1 Arpita
4 1 Sujon
5 2 Arpan
6 3 Jayanti
I am new to SQL and just couldn't find what to use or how to get those results. Is it worth a stored procedure with table valued variable, or just a Tsql select query will be enough. Any help is most welcome.
All I have done is-
Select Ep.emp_id,ep.emp_eame
From Emp as E
Inner Join Emp as Ep on Ep.reports_to=E.Emp_id
Where E.reports_to=1 or E.emp_id=1;
but this is accurate upto 2 level and I cant even generate the hierarchy_level no.
Any suggestion, idea............ will be most helpfull.........
You could use a recursive CTE:
; with CTE as
(
select emp_id
, reports_to
, emp_name
, 1 as level
from Emp
where emp_name = 'Sumanta'
union all
select child.emp_id
, child.reports_to
, child.emp_name
, level + 1
from Emp child
join CTE parent
on child.reports_to = parent.emp_id
)
select *
from CTE
Example at SQL Fiddle.
Using Common_Table_Expression we can write like this
WITH Employee_CTE(employeeid,hierarchy_level,name) AS
(
SELECT employeeid,1 as level,name from employee where employeeid=1
UNION ALL
SELECT e.employeeid,level +1, e.name
from employee e
INNER JOIN Employee_CTE c ON e.employeeid = c.managerid
)
SELECT * FROM Employee_CTE order by employeeid