Option 1
You want employees that are not John Smith
:
SELECT
TgtEmp.EmpNum
, TgtEmp.Fname
, TgtEmp.Lname
FROM
T1 AS TgtEmp
WHERE
NOT (TgtEmp.Fname = 'John' AND TgtEmp.Lname = 'Smith')
;
They each must have some projects:
...
WHERE
NOT (TgtEmp.Fname = 'John' AND TgtEmp.Lname = 'Smith')
AND EXISTS
(
SELECT
...
FROM
T2 AS TgtProjEmp
WHERE
TgtProjEmp.EmpNum = TgtEmp.EmpNum
...
)
And the list of those projects must intersect with the list of projects done by John(s) Smith(s):
...
AND EXISTS
(
SELECT
TgtProjEmp.ProjNum
FROM
T2 AS TgtProjEmp
WHERE
TgtProjEmp.EmpNum = TgtEmp.EmpNum
INTERSECT
SELECT
SrcProjEmp.ProjNum
FROM
T2 AS SrcProjEmp
WHERE
SrcProjEmp.EmpNum IN
(
SELECT
SrcEmp.EmpNum
FROM
T1 AS SrcEmp
WHERE
(SrcEmp.Fname = 'John' AND SrcEmp.Lname = 'Smith')
)
)
Putting everything together, we will get something like this:
SELECT
TgtEmp.EmpNum
, TgtEmp.Fname
, TgtEmp.Lname
FROM
T1 AS TgtEmp
WHERE
NOT (TgtEmp.Fname = 'John' AND TgtEmp.Lname = 'Smith')
AND EXISTS
(
SELECT
TgtProjEmp.ProjNum
FROM
T2 AS TgtProjEmp
WHERE
TgtProjEmp.EmpNum = TgtEmp.EmpNum
INTERSECT
SELECT
SrcProjEmp.ProjNum
FROM
T2 AS SrcProjEmp
WHERE
SrcProjEmp.EmpNum IN
(
SELECT
SrcEmp.EmpNum
FROM
T1 AS SrcEmp
WHERE
(SrcEmp.Fname = 'John' AND SrcEmp.Lname = 'Smith')
)
)
;
Option 2
That is not the only option. There is also an approach that does not involve referencing the tables multiple times. First, you join the two tables together and use window aggregation to mark projects that were done by (a) John Smith.
SELECT
Emp.EmpNum
, Emp.Fname
, Emp.Lname
, MAX(CASE WHEN Emp.Fname = 'John' AND Emp.Lname = 'Smith' THEN 1 END)
OVER (PARTITION BY ProjEmp.ProjNum) AS HasProjectDoneByJohnSmith
FROM
T1 AS Emp
INNER JOIN T2 AS ProjEmp ON Emp.EmpNum = ProjEmp.EmpNum
Then you use the above as either a derived table or a CTE and pull all the distinct employee names that are not John Smith where HasProjectDoneByJohnSmith
equals to 1:
derived table:
SELECT DISTINCT
EmpNum
, Fname
, Lname
FROM
(
SELECT
Emp.EmpNum
, Emp.Fname
, Emp.Lname
, MAX(CASE WHEN Emp.Fname = 'John' AND Emp.Lname = 'Smith' THEN 1 END)
OVER (PARTITION BY ProjEmp.ProjNum) AS HasProjectDoneByJohnSmith
FROM
T1 AS Emp
INNER JOIN T2 AS ProjEmp ON Emp.EmpNum = ProjEmp.EmpNum
) AS derived
WHERE
NOT (Fname = 'John' AND Lname = 'Smith')
AND HasProjectDoneByJohnSmith = 1
;
CTE:
WITH
EmployeeProjects AS
(
SELECT
Emp.EmpNum
, Emp.Fname
, Emp.Lname
, MAX(CASE WHEN Emp.Fname = 'John' AND Emp.Lname = 'Smith' THEN 1 END)
OVER (PARTITION BY ProjEmp.ProjNum) AS HasProjectDoneByJohnSmith
FROM
T1 AS Emp
INNER JOIN T2 AS ProjEmp ON Emp.EmpNum = ProjEmp.EmpNum
)
SELECT DISTINCT
EmpNum
, Fname
, Lname
FROM
EmployeeProjects
WHERE
NOT (Fname = 'John' AND Lname = 'Smith')
AND HasProjectDoneByJohnSmith = 1
;
All three final queries can be found in this live demo at db<>fiddle.