SQL to find table entries by consulting foreign keys - sql

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

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

Select value from 2 tables with condition

I want to select values Employee ID, employee first name, project name from tables employee and project of the employee assigned to more than one project.
Thanks everybody I can solve them and sorry about this question is not clear
You must use a JOIN
select EmplyoeeID, FirstName, ProjectName
from EmployeeDetail
join ProjectDetail on EmplyoeeDetailID = EmployeeID
where (select count(*) from ProjectDetail where EmplyoeeDetailID = EmployeeID) > 1
Please read more about joins here: https://www.w3schools.com/sql/sql_join.asp
Try this (a simple INNER JOIN)
SELECT e.EmployeeID, e.firstName, p.ProjectName
FROM Employee e
JOIN ProjectDetail p
ON e.EmployeeID = p.EmployeeDetailID
If you want only employees with more than 1 project
SELECT e.EmployeeID, e.firstName, p.ProjectName
FROM Employee e
JOIN ProjectDetail p
ON e.EmployeeID = p.EmployeeDetailID
WHERE
(SELECT COUNT(1) FROM ProjectDetail p2
WHERE p2.EmployeeDetailID = p.EmployeeDetailID) > 1
A window function is probably the most efficient
SELECT
e.EmployeeID,
e.firstName,
p.ProjectName
FROM Employee e
JOIN (
SELECT p.*,
count = COUNT(*) OVER (PARTITION BY p.EmployeeDetailID)
FROM ProjectDetail p
) p ON e.EmployeeID = p.EmployeeDetailID AND p.count > 1;

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());

I need sql query to merge info from 2 tables

i`m new in SQL and i need a tip. I got 2 tables ( employee and department ),
employee table as E:
id (int), name(nvarchar), gender(nvarchar), departmentID(int), dateofbirth(datetime)
department table as D :
dep_id(int), name(nvarchar), location(nvarchar), boss_id(int)
That`s what i need as output table:
E.id / E.name / D.name / D.location / (and last which i cant get with simple join is:) D.boss.name (not simple boss id but real employee name from E table)
Just simple question for advanced people :-)
Join the table a second time for the boss. (This is assuming that boss_id FK's to Employee)
SELECT
E.Id,
E.Name,
D.Name,
D.Location,
B.Name
FROM Employee E
INNER JOIN Department D on E.DepartmentID = D.Dep_id
INNER JOIN Employee B ON D.Boss_id = B.Id
You can write a query using cte as well:
WITH CTE AS(
Select
e.ID,
e.name,
d.boss_id,
d.Location as DepartmentLocation,
d.name as DepartmentName
From Employee e
INNER JOIN Department d on d.boss_id =E.id
)
Select c.id, c.name, e.name as BossName, c.DepartmentLocation, c.DepartmentName
from cte c
Inner Join Employee e1 on e1.id=c.boss_id
SELECT e.Id, e.Name, d.Name, d.Location,
(
SELECT e2.Name
FROM tblEmployee as e2
WHERE e2.id = d.boss_id
) AS [Boss name]
FROM tblEmployee as e
INNER JOIN tblDepartment as d
ON e.DepartmentID = d.dep_ID

SQL Server 2005 - Nested recursive query :(

I have a query that I need to execute that I do not know how to structure.
I have a table called Employees. I have another table called Company. There is a third table called Files. As you can imagine, a Company has Employees, and Employees have Files.
I need to list out all of the Employees in my database. The challenge is, I need to list the total number of Files in the same company as the Employee. I have tried variations on the following without any luck:
SELECT
e.FirstName,
e.LastName,
e.Company,
(SELECT COUNT(*) FROM Files f WHERE f.EmployeeID IN (SELECT [ID] FROM Employees e2 WHERE e2.CompanyID=e.CompanyID)) as 'FileCount'
FROM
Employees e
What am I doing wrong? Thank you!
Try this:
SELECT
e.FirstName,
e.LastName,
e.Company,
(
SELECT COUNT(*)
FROM Files f
JOIN Employees e2 ON f.EmployeeID = e2.id
WHERE e2.CompanyID = e.CompanyID
) as 'FileCount'
FROM
Employees e
There are a lot of ways to get that. If the performance is a concern, this is more optimal according to estimated execution plan costs.
SELECT
e.FirstName,
e.LastName,
e.Company,
COUNT(f.FileId)
FROM
Employees e
INNER JOIN Files f ON e.EmployeeID = f.EmployeeID
GROUP BY
e.FirstName,
e.LastName,
e.Company
A solution with no correlation in SELECT clause. Probably quicker...
SELECT
e.FirstName,
e.LastName,
e.Company,
foo.FileCount
FROM
Employees e
JOIN
(
SELECT
COUNT(*) AS FileCount, --OR COUNT(DISTINCT something) ?
e2.Company, f.EmployeeID
FROM
Files f JOIN Employees e2 ON f.EmployeeID = e2.id
GROUP BY
e2.Company, f.EmployeeID
) foo ON e.Company = foo.Company AND e.id = foo.EmployeeID
How about:
SELECT
e.FirstName,
e.LastName,
e.Company,
select count(*) from Files f, Employees e where f.EmployeeID=e.EmployeeID and e.CompanyID=emp.CompanyID
FROM
Employees emp
WITH FilesPerCompany (CompanyID, NumberOfFiles)
AS (SELECT c.ID AS CompanyID,
COUNT(*) AS NumberOfFiles
FROM Companies c
INNER JOIN Employees e ON c.ID = e.CompanyID
INNER JOIN Files f ON e.ID = f.EmployeeID
GROUP BY c.ID
)
SELECT e.FirstName,
e.LastName,
e.Company,
COALESCE(s.NumberOfFiles, 0) AS NumberOfFilesPerCompany
FROM Employees e
LEFT JOIN FilesPerCompany s
ON s.CompanyID = e.CompanyID
The following statement uses recursive joins to iterate down employees who manage other employees who manage other employees .... etc. Our structure is a little convoluted as the management structure is role based which actually allows an employee to have more than 1 manager. You can add a reference to Files within this recursion.
WITH Manager as
(SELECT c.Forenames + ' ' + c.Surname as Employee,
c2.Forenames + ' ' + c2.Surname AS Manages,
c.accountid AS AccountID, c.[Status] AS [Status]
FROM [intranet].[dbo].[tblContact] c
LEFT JOIN tblContactPost cp ON cp.contactid = c.contactid
LEFT JOIN tblPost p ON p.ParentRoleId = cp.RoleID AND p.ParentPostArea = cp.PostArea AND p.ParentPostNo = cp.PostNo
INNER JOIN tblContactPost cp2 ON cp2.RoleId = p.RoleId AND cp2.PostArea = p.PostArea AND cp2.PostNo = p.PostNo
INNER JOIN tblContact c2 ON c2.ContactID = cp2.ContactId
)
,jn AS
(SELECT Employee, Manages
FROM Manager
Where AccountID = 'ad\lgardner' AND [Status] = 'A'
UNION ALL
SELECT c.Employee, c.Manages
FROM jn as p JOIN Manager AS c
ON c.Employee = p.Manages
)
SELECT jn.Employee, jn.Manages
From jn
Order BY 1