Find distinct values from the generated result set in SQL - sql

Two select statements union together with multiple inner joins.
Just need to find out the distinct elements out of this result sets.
I could have write distinct when selecting columns but this is not what I want.
SELECT
employeeid, employeename
FROM
employee AS emp
INNER JOIN
department AS dep ON emp.employeeid = dep.employeeid
INNER JOIN
company AS comp ON emp.companyid = comp.companyid
UNION
SELECT
employeeid, employeename
FROM
employer AS emp
INNER JOIN
category AS cat ON emp.employeeid = cat.employeeid
INNER JOIN
business AS busi ON emp.companyid = busi.companyid

SELECT DISTINCT employeeid, employeename
FROM
(
SELECT
employeeid, employeename
FROM
employee AS emp
INNER JOIN
department AS dep ON emp.employeeid = dep.employeeid
INNER JOIN
company AS comp ON emp.companyid = comp.companyid
UNION
SELECT
employeeid, employeename
FROM
employer AS emp
INNER JOIN
category AS cat ON emp.employeeid = cat.employeeid
INNER JOIN
business AS busi ON emp.companyid = busi.companyid
) AS t

Related

find all employees' names who has a manager that lives in the same city as them

I am trying to figure out how to "find all employees' name who has a manager that lives in the same city as them." For this problem, we have two tables. We need to make a query.
"employee"
The employee table that we can refer to has both normal employees and managers
employeeid
name
projectid
city
1
jeff
1
new york
2
larry
1
new york
3
Linda
2
detroit
4
tom
2
LA
"Managertable"
Our manager table which we can refer to with mangerid = employeeid
projectid
mangerid
1
2
2
3
Right now I have found a way to get just the employees and filter out the managers, but now I am trying to figure out the next step to get to the comparison of managers and employees. Would this just be another subquery?
SELECT name
FROM employee e
WHERE employeeid not in(
SELECT mangerid
FROM Managertable pm
INNER JOIN employee e
ON pm.mangerid= e.employeeid);
Expected result :
employee name
jeff
I think the easient way to achieve this would be like this:
SELECT
e.*
FROM employee e
inner join Managertable mt on e.projectid = mt.projectid
inner join employee manager on mt.mangerid = manager.employeeid
WHERE
e.city = manager.city
and e.employeeid <> manager.employeeid;
One approach is a correlated subquery in which we look up the employee's manager's city.
select e.name
from employee e
where city =
(
select m.city
from managertable mt
join employee m on m.employeeid = mt.managerid
where mt.projectid = e.projectid
and m.employeeid <> e.employeeid
);
The same thing can be written with an EXISTS clause, if you like that better.
Based off the table structure you're showing, something like this might work
First find the employee ids of employees who have managers in the same city, then join it back on employee to retrieve all data from the table
;WITH same_city AS (
SELECT DISTINCT e.employeeid
FROM employee AS e
INNER JOIN managertable AS mt ON e.projectid = mt.projectid
INNER JOIN employee AS m ON mt.managerid = e.employeeid
WHERE e.city = m.city
)
SELECT e.*
FROM employee
INNER JOIN same_city AS sc ON e.employeeid = sc.employeeid
I don't see how projectid is relevant in your question because you didn't mention that as a requirement or restriction. Here's a method using a CTE to get the managers and their cities, then join to it to find employees who live in the same city as a manager.
with all_managers as (
select distinct m.managerid, e.city
from manager m
join employee e
on m.managerid = e.employeeid
)
select e.name
from employee e
join all_managers a
on e.city = a.city
and e.employeeid <> a.managerid;
name
jeff
But it you want us to assume that an employee reports to only that manager as listed in the projectid, then here's a modification to ensure that is met:
with all_managers as (
select distinct m.managerid, e.city, e.projectid
from manager m
join employee e
on m.managerid = e.employeeid
)
select e.name
from employee e
join all_managers a
on e.city = a.city
and e.projectid = a.projectid
and e.employeeid <> a.managerid;
View on DB Fiddle
You just need two joins:
one between "managers" and "employees" to gather managers information
one between "managers" and "employees" to gather employees information with respect to the manager's projectid and city.
SELECT employees.name
FROM managers
INNER JOIN employees managers_info
ON managers.mangerid = managers_info.employeeid
INNER JOIN employees
ON managers.projectid = employees.projectid
AND managers_info.employeeid <> employees.employeeid
AND managers_info.city = employees.city

Join tables and Concatenate Multiple Rows Within Single Row

Join multiple table and concatenate multiple rows into one for distinct department names.
I was able to do it on table EmpDepartment but I need to join all table.
Expected output like this.
Need Query
EmpID
EmpName
DepartmentName
1
A
q,w,e
2
B
Null
SELECT
p.EmpID,
EmpName,
STRING_AGG(DepartmentName,',') as DepartmentName
FROM
EmpPayroll p
LEFT OUTER JOIN
EmpDepartment e on e.EmpID=p.EmpID
LEFT OUTER JOIN
Department d on d.deptID=e.deptID
GROUP BY
p.EmpID,
EmpName
if you're on SQL Server 2017 or later.
https://learn.microsoft.com/en-us/sql/t-sql/functions/string-agg-transact-sql?view=sql-server-ver15
I updated as per your request.
If you are using SQL Server 2017 and above Versions
SELECT ED.EmpId
,EP.EmpName
,STRING_AGG(D.DepartmentName,',') AS DepartmentName
FROM EmpPayroll EP
LEFT JOIN EmpDepartment ED
ON EP.EmpId = ED.EmpId
LEFT JOIN Department D
ON D.DeptId = ED.DeptId
Group By ED.EmpId, EP.EmpName
and for SQL Server 2016 and Below Versions
;WITH Partitioned AS
(
SELECT EP.EmpId, EP.EmpName,D.DepartmentName,
ROW_NUMBER() OVER (PARTITION BY ED.EmpId ORDER BY D.DepartmentName) AS NameNumber,
COUNT(*) OVER (PARTITION BY ED.EmpId) AS NameCount
FROM EmpPayroll EP
LEFT JOIN EmpDepartment ED
ON EP.EmpId = ED.EmpId
LEFT JOIN Department D
ON D.DeptId = ED.DeptId
),
Concatenated AS
(
SELECT
EmpId,
CAST(DepartmentName AS nvarchar) AS DepartmentName,
EmpName,
NameNumber,
NameCount
FROM Partitioned
WHERE NameNumber = 1
UNION ALL
SELECT
P.EmpId,
CAST(P.DepartmentName + ', ' + C.DepartmentName AS nvarchar),
P.EmpName,
P.NameNumber,
P.NameCount
FROM Partitioned AS P
INNER JOIN Concatenated AS C
ON P.EmpId = C.EmpId
AND P.NameNumber = C.NameNumber + 1
)
SELECT
EmpId,
EmpName,
DepartmentName
FROM Concatenated
WHERE NameNumber = NameCount

How to show the employess who have only one project, and also their project. Many to Many relationship problem

Project Table:
Employee Table
Connector Table:
Therea are 6 employees who have only one project
one of the prjects is P2, it has 5 employees
and the other project is P3 which has 1 employee
Select * from Emp
Select * from Project
Select * from PrEmpConnector
------------------------------------------------
Select t.EmpId as Employee_Id, t.Project_Name
from (
Select
PE.EmpId,
P.Project_Name
from PrEmpConnector as PE
inner join Project as P on P.Id in(
Select sum(t.ProjectId)
from PrEmpConnector as t
group by t.EmpId
having COUNT(t.EmpId) = 1
)
) as t
group by t.Project_Name, t.EmpId
having t.EmpId in (
Select t.EmpId
from PrEmpConnector as t
group by t.EmpId
having COUNT(*) = 1
)
select emp.name,emp.surname,project.project_name from
PrEmpConnector
inner join emp on emp.id=PrEmpConnector.emp_id
inner join Project on Project.id=PrEmpConnector.projectid
where emp.empid in (
select emp_id from PrEmpConnector
group by emp_id having count(projectid) =1)
If you are looking for employees that only work on one project, you can join the three tables, aggregate by employee, and filter on groups that contain only one record with a having clause:
select
e.id employee_id,
e.name employee_name,
min(p.id) project_id,
min(p.project_name) project_name
from project p
inner join connector c on c.projectId = p.id
inner join employee e on e.id = c.employeeId
group by e.id, e.name
having count(*) = 1

SQL to find table entries by consulting foreign keys

I have 4 tables as below:
Company: companyid, name
Employees: employeeid, name, companyid
Jobs: jobid, title, companyid
LinkEmpolyeeJob: employeeid, jobid
I want to identify invalid entries in the LinkEmpolyeeJob table where the employee and the job are from different company.
I want to avoid query like below because it was too slow:
select *
from LinkEmpolyeeJob
where (employeeid, jobid) not in (select a.employeeid, b.jobid
from Employees a, Jobs b
where a.companyid = b.companyid);
Anyone help? Thanks!
Try using joins:
select e.*, j.*
from LinkEmpolyeeJob lej join
Employees e
on lej.employeeid = e.employeeid join
Jobs j
on lej.jobid = j.jobid
where e.companyid <> j.companyid
Try using LEFT JOINs like below. (Did not test the query, but should give you idea)
select *
from LinkEmpolyeeJob lej
left join employees e on lej.employeeid = e.employeeid
left join jobs j on e.companyid = j.companyid and lef.jobid = j.jobid
where e.employeeid is null and j.jobid is null

Query to get employee of different departments

I have 3 tables: Employee, Department and employeeProject.
The relation between employee and employeeproject is one-to-many. The relation between employee and department is many-to-one.
I want to write a query to select 10 employees who have worked in projects 3 and 4. The query should return employees of different departments if possible.
The query below kind of works. The only problem is that the relationship between employee and employeeproject is one-to-many, so it might return the same employee number multiple times.
I cannot use distinct because all fields in the order by clause should be used in select when using distinct.
select top 10 empid from employee e
inner join department d on d.depId=e.depid
inner join employeeProject p on p.empid=e.empid
where p.projectID in (3,4)
order by row_number() over(partition by e.depId order by e.empid)
Bit of a guess, but use an EXISTS?
SELECT TOP 10 e.empid
FROM employee e
JOIN department d ON e.depid = d.depid
WHERE EXISTS (SELECT 1
FROM employeeproject p
WHERE p.emdid = e.empid
AND p.projectid IN (3,4))
ORDER BY e.depid, e.empid;
I suggest aggregating by employee, and then using an assertion the HAVING clause:
SELECT TOP 10 e.empid
FROM employee e
INNER JOIN department d
ON d.depId = e.depid
INNER JOIN employeeProject p
ON p.empid = e.empid
WHERE
p.projectID IN (3,4)
GROUP BY
e.empid
HAVING
MIN(p.projectID) <> MAX(p.projectID);
If the minimum and maximum projectID are not equal for a given employee, after restricting to only projects 3 and 4, then it implies that this employee meets the criteria.
Why not just use select distinct?
select distinct top 10 empid
from employee e inner join
employeeProject p
on p.empid = e.empid
where p.projectID in (3, 4)
order by row_number() over (partition by e.depId order by e.empid);
Note that the department table is not needed.
Alternatively,
select top (10) e.*
from employee e
where exists (select 1
from employeeprojects ep
where p.emdid = e.empid and
p.projectid in (3, 4)
)
order by row_number() over (partition by e.depid order by newid());