Select parent and child from the same table - sql-server-2005

I have a emp table,
CREATE TABLE [dbo].[Emp](
[EmpId] [int] NULL,
[EmpName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[ManagerId] [int] NULL
) ON [PRIMARY]
Now, insert below values into the table
Insert Into Emp Values(1,'A',0)
Insert Into Emp Values(2,'B',1)
Insert Into Emp Values(3,'C',2)
Insert Into Emp Values(4,'D',2)
Insert Into Emp Values(5,'E',4)
Insert Into Emp Values(6,'F',4)
Insert Into Emp Values(7,'G',4)
Insert Into Emp Values(8,'H',6)
Insert Into Emp Values(9,'I',5)
Insert Into Emp Values(10,'J',7)
Insert Into Emp Values(11,'K',4)
I want to list employee name and their manager name in select statement.
What I am doing now is creating a temporary table which has all manager name and their Id.
Then getting the name from the manager table based on Id.
But I know this is not a correct way, in fact it is complex.

You should use a recursive CTE (Common Table Expression) for this:
-- define the recursive CTE and give it a name
;WITH Hierarchy AS
(
-- "anchor" - top-level rows to select, here those with ManagerId = 0
SELECT EmpId, EmpName, NULL AS 'MgrId', CAST(NULL AS NVARCHAR(50)) AS 'MgrName', 1 AS 'Level'
FROM dbo.Emp
WHERE ManagerId = 0
UNION ALL
-- recursive part - join an employee to its manager via ManagerId -> mgr.EmpId
SELECT e.EmpId, e.EmpName, mgr.EmpId, mgr.EmpName, mgr.Level + 1 AS 'Level'
FROM dbo.Emp e
INNER JOIN Hierarchy mgr ON e.ManagerId = mgr.EmpId
)
SELECT * FROM Hierarchy

You are correct: you don't have to use a temporary table just for this. Try using recursive queries. Take a look at this link on MSDN. There is an example with ManagerId/EmployeeID. Just as in your query.

Related

using FUNCTION -SQL Server query to find the current post of the employee [duplicate]

This question already has answers here:
Retrieving last record in each group from database - SQL Server 2005/2008
(2 answers)
Closed 2 years ago.
Can you tell how to find the last updated post of the employee from the table. Two tables :Employee and EmployeeDetails. Employee fields are: EmployeeID ,EmployeeName EmployeeDetails fields are: EmployeeID, Designation, PromotionDate.
How to find the current Designation of an employee if we give an EmployeeID. Using function. I want to create a simple function to get the Designation according to the current Designation (Latest PromotionDate ) using the EmployeeID, then join with Employee table.
DROP TABLE IF EXISTS Employee
CREATE TABLE Employee
(
EmployeeID INT NOT NULL PRIMARY KEY IDENTITY(1000,1),
EmployeeName VARCHAR(25)
)
INSERT INTO Employee VALUES('AAA');
INSERT INTO Employee VALUES('LAAA');
INSERT INTO Employee VALUES('RSSS');
INSERT INTO Employee VALUES('SEEE');
INSERT INTO Employee VALUES('CFFF');
INSERT INTO Employee VALUES('SEEEW');
INSERT INTO Employee VALUES('MCCC');
INSERT INTO Employee VALUES('DERR');
INSERT INTO Employee VALUES('DERR');
INSERT INTO Employee VALUES('DERW');
SELECT * FROM Employee
DROP TABLE EmployeeDetails
CREATE TABLE EmployeeDetails
(
EmployeeID INT FOREIGN KEY REFERENCES Employee(EmployeeID),
Designation VARCHAR(25),
PromotionDate Date
)
INSERT INTO EmployeeDetails VALUES(1000,'www','2020-11-20');
INSERT INTO EmployeeDetails VALUES(1000,'qqq','2020-01-23');
INSERT INTO EmployeeDetails VALUES(1009,'qqq','2020-09-20');
SELECT * FROM EmployeeDetails
SELECT
E.EmployeeID,
E.EmployeeName,
ED.Designation, ED.PromotionDate
FROM
Employee E
JOIN
EmployeeDetails ED ON E.EmployeeID = ED.EmployeeID
I wrote a function for this, but I don't know how to incorporate it with the query:
CREATE FUNCTION GetOnlyTheCurrentPost
( #EmpID INT)
RETURNS DATE
AS
BEGIN
DECLARE #PromoDate DATE
SELECT #PromoDate= MAX(PromotionDate)
FROM EmployeeDetails
WHERE EmployeeID = #EmpID
RETURN(#PromoDate)
END
I changed the function like this as below
ALTER FUNCTION [dbo].[GetOnlyTheCurrentPost]
( #PromoDate DATE)
RETURNS DATE
AS
BEGIN
SELECT #PromoDate= MAX(PromotionDate)
FROM EmployeeDetails
RETURN(#PromoDate)
END
SELECT
E.EmployeeID,
ED.Designation,[dbo].[GetOnlyTheCurrentPost](ED.PromotionDate) AS LatestPost
FROM
Employee E
JOIN
EmployeeDetails ED
ON E.EmployeeID = ED.EmployeeID
This will show all the records not only the latest post but also every records.
Again, I changed my function. I want to get the current Designation, if i give the EmployeeID Like, SELECT [dbo].[GetOnlyTheCurrentDesignation](1011). Output should be printed according to the given corresponding EmployeeID Output : ProjectManager
ALTER FUNCTION GetOnlyTheCurrentDesignation
(#EmpID INT)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #Designation VARCHAR(25)
SELECT #Designation=Designation, MAX(PromotionDate)
FROM EmployeeDetails
WHERE EmployeeID = #EmpID
RETURN(#Designation)
END
Please tell me a solution to fix this
Try something like this:
SELECT
E.EmployeeID,
E.EmployeeName,
ED.Designation, ED.PromotionDate
FROM
Employee E
JOIN
(SELECT * FROM EmployeeDetails ED2
WHERE PromotionDate = (SELECT MAX(PromotionDate)
FROM EmployeeDetails
WHERE EmployeeID = ED2.EmployeeID)) ED
ON E.EmployeeID = ED.EmployeeID

How to count records in SQL

Edit: Schema taken/extrapolated from comment below
create table #employees
(
Emp_ID int,
Name varchar(50),
Dept_ID int,
);
create table #departments
(
Dept_ID int,
Dept_Name varchar(50)
);
How do I count the number of employees from table employees that work in each department in table departments and include all departments that have no employees working in them.
Welcome to SO.
This problem is quite simple to solve. The steps would be as follows:
Join the Departments table to the Employees table on the Dept_ID column.
SELECT the Dept_ID and Count() and GROUP BY the Dept_ID field.
In order to return Departments without employees you need to LEFT JOIN this aggregation to the Departments table on the Dept_ID column.
In order to return the value of 0 for departments without employees, use the ISNULL() function.
Please see the below sample script using your schema. Note that this script is written in T-SQL, as you did not mention your server type.
create table #employees
(
Emp_ID int,
Name varchar(50),
Dept_ID int,
);
create table #departments
(
Dept_ID int,
Dept_Name varchar(50)
);
insert into #employees
select 1, 'Pim', 1
union all
select 2, 'Salma', 2;
insert into #departments
select 1, 'IT'
union all
select 2, 'Marketing'
union all
select 3, 'Design'
select
d1.Dept_Name
,isnull(d2.EmployeeCount, 0) as EmployeeCount
from
#departments d1
left join
(
select
d.Dept_ID
,count(e.Dept_ID) as EmployeeCount
from
#departments d
join
#employees e
on e.Dept_ID = d.Dept_ID
group by
d.Dept_ID
)
d2
on d2.Dept_ID = d1.Dept_ID
drop table #employees
drop table #departments
As you have supplied no data please try below and see if this works for you
Create the tables, I don't know if this is similar to your table structure
CREATE TABLE tbl_EMPLOYEES (Empl_Name nvarchar(20), Dept nvarchar(15))
CREATE TABLE tbl_DEPARTMENT (Dept nvarchar(15))
Populate these tables
INSERT INTO tbl_EMPLOYEES Values ('James', 'Finance')
INSERT INTO tbl_EMPLOYEES Values ('Tim', 'HR')
INSERT INTO tbl_EMPLOYEES Values ('Sally', 'Finance')
INSERT INTO tbl_EMPLOYEES Values ('Bob', 'Sales')
INSERT INTO tbl_EMPLOYEES Values ('Sam', 'HR')
INSERT INTO tbl_EMPLOYEES Values ('James', 'Finance')
INSERT INTO tbl_DEPARTMENT Values ('Finance')
INSERT INTO tbl_DEPARTMENT Values ('HR')
INSERT INTO tbl_DEPARTMENT Values ('Sales')
INSERT INTO tbl_DEPARTMENT Values ('IT')
This query will give you the number of people in each department
SELECT Dept, Count(Dept) AS Count
FROM
(
SELECT Dept
FROM tbl_EMPLOYEES
) AS Blah_Blah
GROUP BY Dept

Self Join in SQL

I have an Employee table with few records in it, from which I want to get all the employees who work in the department where employee "scott" works and those with department number as 20.
can you give a try on the following query and let me know if this worked for you
select * from employee where deptno in (select deptno from employee where name ='scott')
Not very Descriptive, But u may try this as per the Information u've provided,
Create Table #Employees
(Id int,
EmpName nvarchar(20),
Deptno int
)
Insert into #Employees Values(1,'Henry',10)
Insert into #Employees Values(2,'Mark',20)
Insert into #Employees Values(3,'Scott',20)
Insert into #Employees Values(4,'David',10)
Insert into #Employees Values(5,'Peter',30)
Insert into #Employees Values(6,'Mary',20)
Insert into #Employees Values(7,'John',30)
Select EmpName From #Employees
Where Deptno In(Select Deptno from #Employees Where EmpName = 'Scott')
And for Complete information of Employees,
Select * From #Employees
Where Deptno In(Select Deptno from #Employees Where EmpName = 'Scott')
For example the following query returns employee names and their manager names for whom they are working. Copy & Paste the following sql, I think it may help the purpose.
Create table Emp
(
empid int primary key,
name varchar(50),
mgrid int
)
Insert into Emp(empid,name,mgrid)
values (1001,'Manish Agrahari',1001);
Insert into Emp(empid,name,mgrid)values (1002,'Deepti',1001);
Insert into Emp(empid,name,mgrid)values (1003,'Amit',1001);
Insert into Emp(empid,name,mgrid)values (1004,'Sandy',1002);
Insert into Emp(empid,name,mgrid)values (1005,'Ankit',1003);
Insert into Emp(empid,name,mgrid)values (1006,'Kapil',1002);
Run The following SQL and see the result:
SELECT e.empid, e.name, m.name "Manager" FROM Emp e, Emp m WHERE e.mgrid=m.empid;

How to solve single-row subquery returns more than one row

I have an employee table and it contains salary table. I want to give %10 increase to all current employees. I tried to update all employees' salary dates to specific date but I encountered problem with single-row subquery.
My database like this:
CREATE TYPE TEMPORAL_VARCHAR AS OBJECT (
VALID_TIME_LOWER_BOUND DATE,
VALID_TIME_UPPER_BOUND DATE,
VALUE_PART VARCHAR2(50) );
CREATE TYPE TEMPORAL_NUMBER AS OBJECT (
VALID_TIME_LOWER_BOUND DATE,
VALID_TIME_UPPER_BOUND DATE,
VALUE_PART NUMBER );
CREATE TYPE NAME_TYPE AS TABLE OF TEMPORAL_VARCHAR;
CREATE TYPE ADDRESS_TYPE AS TABLE OF TEMPORAL_VARCHAR;
CREATE TYPE DEPARTMENT_TYPE AS TABLE OF TEMPORAL_VARCHAR;
CREATE TYPE MANAGER_TYPE AS TABLE OF TEMPORAL_VARCHAR;
CREATE TYPE SALARY_TYPE AS TABLE OF TEMPORAL_NUMBER;
CREATE TABLE EMPLOYEE (
SSN NUMBER primary key,
NAME NAME_TYPE,
ADDRESS ADDRESS_TYPE ,
BIRTH_DATE DATE,
MANAGER MANAGER_TYPE ,
DEPARTMENT DEPARTMENT_TYPE,
SALARY SALARY_TYPE
)
NESTED TABLE NAME STORE AS NAME_TABLE,
NESTED TABLE ADDRESS STORE AS ADDRESS_TABLE,
NESTED TABLE MANAGER STORE AS MANAGER_TABLE,
NESTED TABLE DEPARTMENT STORE AS DEPARTMENT_TABLE,
NESTED TABLE SALARY STORE AS SALARY_TABLE
;
How to solve this problem? I tried to do this
UPDATE TABLE(
SELECT E.SALARY
FROM EMPLOYEE E
) SAL
SET SAL.VALID_TIME_UPPER_BOUND = '11.16.2015'
WHERE SAL.VALID_TIME_UPPER_BOUND = TO_DATE('12.31.9999','MM.DD.YYYY');
1st it can be duplicate
2nd see sample here
3rd in your code you need bring the where condition into select
UPDATE TABLE(
SELECT E.SALARY
FROM EMPLOYEE E
WHERE ssn in (SELECT ssn FROM EMPLOYEE e
WHERE to_date('01.01.2015','mm.dd.yyyy') in (
SELECT VALID_TIME_UPPER_BOUND FROM TABLE(e.salary)
)
)
) SAL
SET SAL.VALID_TIME_UPPER_BOUND = to_date('01.01.9999','mm.dd.yyyy')
test data
INSERT INTO EMPLOYEE(SSN, salary) values (1, SALARY_TYPE ());
INSERT INTO EMPLOYEE(SSN, salary) values (2, SALARY_TYPE ());
INSERT INTO EMPLOYEE(SSN, salary) values (3, SALARY_TYPE ());
INSERT INTO TABLE(SELECT salary FROM EMPLOYEE
WHERE ssn = 1)
VALUES (to_date('01.01.2005','mm.dd.yyyy'), to_date('01.01.2015','mm.dd.yyyy'), 1);
INSERT INTO TABLE(SELECT salary FROM EMPLOYEE
WHERE ssn = 2)
VALUES (to_date('02.02.2005','mm.dd.yyyy'), to_date('02.02.2015','mm.dd.yyyy'), 2);
INSERT INTO TABLE(SELECT salary FROM EMPLOYEE
WHERE ssn = 3)
VALUES (to_date('03.03.2005','mm.dd.yyyy'), to_date('03.03.2015','mm.dd.yyyy'), 3);
p.s do you really need the complexity?
I solved my problem using iteration like this
BEGIN
FOR employees IN (SELECT SSN FROM EMPLOYEE)
LOOP
UPDATE TABLE(
SELECT E.SALARY
FROM EMPLOYEE E
WHERE E.SSN = employees.SSN
) SAL
SET SAL.VALID_TIME_UPPER_BOUND = '11.16.2015'
WHERE SAL.VALID_TIME_UPPER_BOUND = TO_DATE('12.31.9999','MM.DD.YYYY');
END LOOP;
END;

Show Manager Name instead of Manager Id in Sql server query

Query
create table Emp(empId int primary key, EmpName varchar(50),MngrID int)
insert into Emp(empId,EmpName,MngrID)values(1,'A',2)
insert into Emp(empId,EmpName,MngrID)values(2,'B',null)
create table Mngr(MngrId int primary key, MngrName varchar(50))
insert into Mngr(MngrId,MngrName)values(1,'m1')
insert into Mngr(MngrId,MngrName)values(2,'m2')
I want to fetch the record in Emp table for MngrId Column that show the name of Manger instead of MngrId.
sql fiddle My fiddle
You need to use a join.
select e.empId, e.EmpName, m.MngrName
from Emp e
inner join Mngr m on m.MngrId = e.MngrID