Subquery with more than one column - sql

I try to build a subquery with more than one column. Like this:
--SELF JOIN:
WITH Employees AS
(
SELECT
e.EmployeeID, e.ManagerID, e.Title,
c.FirstName + ISNULL(' ' + c.MiddleName,'') + ' ' + c.LastName AS EmpName
FROM
Employee AS e
INNER JOIN
Contact AS c ON e.ContactID = c.ContactID
)
SELECT
emp.EmployeeID, emp.ManagerID, emp.EmpName, emp.Title AS EmpTitle,
mgr.EmpName as MgrName, mgr.Title as MgrTitle
FROM
Employees AS Emp
INNER JOIN
Employees AS Mgr ON Emp.ManagerID = Mgr.EmployeeID;
--2
WITH Employees AS
(
SELECT
e.EmployeeID, e.ManagerID, e.Title,
c.FirstName + ISNULL(' ' + c.MiddleName,'') + ' ' + c.LastName AS EmpName
FROM
Employee AS e
INNER JOIN
Contact AS c ON e.ContactID = c.ContactID
)
SELECT
EmployeeID, ManagerID, EmpName, Title
FROM
Employees
WHERE
EmployeeID IN (SELECT EmployeeID, er2.MaritalStatus
FROM Employees AS e
INNER JOIN AdventureWorks2012.HumanResources.Employee AS er2 ON e.ManagerID = er2.BusinessEntityID
WHERE er2.MaritalStatus = 'M');
I want also to show the MarialStatus. But I can't do it this way, because I get the error:
Only one expression can be specified in the select list when the
subquery is not introduced with EXISTS.
But If I can't do it with exists in the subquery. So my question is: what is the proper way that I can select more then one column in the subquery?
Thank you

You can't return 2 values in a sub query.So you will have to remove the MaritalStatus column. That's the problem with your query.
USE tempdb;
WITH
Employees AS(
SELECT e.EmployeeID, e.ManagerID,e.Title,
c.FirstName + ISNULL(' ' + c.MiddleName,'') + ' ' + c.LastName AS EmpName
FROM Employee AS e
INNER JOIN Contact AS c
ON e.ContactID = c.ContactID
)
SELECT emp.EmployeeID, emp.ManagerID, emp.EmpName, emp.Title AS EmpTitle,
mgr.EmpName as MgrName, mgr.Title as MgrTitle
FROM Employees AS Emp INNER JOIN Employees AS Mgr
ON Emp.ManagerID = Mgr.EmployeeID;
--2
WITH Employees AS (
SELECT e.EmployeeID, e.ManagerID,e.Title,
c.FirstName + ISNULL(' ' + c.MiddleName,'') + ' ' + c.LastName AS EmpName
FROM Employee AS e
INNER JOIN Contact AS c
ON e.ContactID = c.ContactID)
SELECT e.EmployeeID, e.ManagerID, e.EmpName, e.Title,er2.MaritalStatus
FROM Employees e
INNER JOIN AdventureWorks2012.HumanResources.Employee AS er2
ON e.ManagerID = er2.BusinessEntityID
WHERE er2.MaritalStatus = 'M');
I don't think you need a subquery there,because INNER JOIN will give you only records if there's a match. So do a INNER JOIN fro the table and put the MaritalStatus column in the select clause

The problem appears to be in your second query. The second column is not necessary in the SELECT. But, you can further simplify the logic by removing the JOIN:
SELECT e.EmployeeID, e.ManagerID, e.EmpName, e.Title
FROM Employees e
WHERE e.ManagerID IN (SELECT er2.BusinessEntityID
FROM AdventureWorks2012.HumanResources.Employee er2
WHERE er2.MaritalStatus = 'M'
);

Related

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;

using where in count sql

I have this SQL which works fine
SELECT COUNT(*) AS total, e.FirstName, e.LastName
FROM [Messages] AS m
INNER JOIN Employees AS e ON m.SenderId = e.UserId
GROUP BY e.EmployeeId, e.FirstName, e.LastName
But I want to also have total unread messages as column.
How can I achieve this in SQL?
SELECT
COUNT(*) AS total,
COUNT(where m.isRead = false) AS totalUnreadMessages,
e.FirstName, e.LastName
FROM
[Messages] AS m
INNER JOIN
Employees AS e ON m.SenderId = e.UserId
GROUP BY
e.EmployeeId, e.FirstName, e.LastName
You are almost there, use a case expression to do conditional counting:
SELECT Count(*) as total,Count(case when m.isRead = false then 1 end) as totalUnreadMessage,
e.FirstName,e.LastName
FROM [Messages] as m
inner join Employees as e on m.SenderId=e.UserId
group by e.EmployeeId, e.FirstName,e.LastName
I would write this as:
SELECT e.FirstName, e.LastName, COUNT(*) as total,
SUM(CASE WHEN m.isRead = 0 THEN 1 ELSE 0 END) as total_unread
FROM [Messages] m JOIN
Employees e
ON m.SenderId = e.UserId
GROUP BY e.EmployeeId, e.FirstName, e.LastName;
You can count them then join them with the original select:
SELECT Count(*) as total,tbNotRead.NotReadNumber AS totalUnreadMessage, e.FirstName,e.LastName
FROM [Messages] as m
INNER JOIN Employees as e ON m.SenderId=e.UserId
LEFT OUTER JOIN
(
SELECT m.Sender, COUNT(*) NotReadNumber
FROM [Messages] msgs
WHERE m.isRead = FALSE
GROUP BY m.Sender
)tbNotRead
ON tbNotRear.Sender = m.sender
GROUP BY e.EmployeeId, e.FirstName,e.LastName, tbNotRead.NotReadNumber

How to SELECT unique rows from 3 JOINED tables

I am trying to check if a persons name appears multiple times in a table aswell as pull additional information (position title, department name, employee number) to limit creating two stored procedures 1. to check if name appears multiple times and 2. to get the additional information after check has been completed.
my current query right now is as follows, which returns multiple rows as the ID I am using to join the tables appears multiple times in one table (an employee can belong to multiple departments, the EmpID occurs here multiple times thyus returning the multiple values).
SELECT c.FirstName+ ' ' + c.LastName as emp_full_name, e.EmployeeNumber,
e.EmpID, dh.PositionTitle, d.Name as deptName, e.isActive
FROM Person.Contact c
INNER JOIN HumanResources.Employee e ON c.ContactID = e.ContactID
INNER JOIN HumanResources.EmployeeDepartmentHistory dh ON e.EmpID = dh.EmpID
INNER JOIN HumanResources.Department d ON dh.DepartmentID = d.DepartmentID
WHERE c.FirstName+ ' ' + c.LastName LIKE #empName
My general table structure is as follows:
Person.Contact
ContactID
FirstName
LastName
HumanResources.Employee
EmpID
EmployeeNumber
isActive
HumanResources.EmployeeDepartmentHistory
DepartmentHistoryId
EmpID
DepartmentID
PositionTitle
HumanResources.Department
DepartmentID
Name
Example Result Set:
John Doe 1234567 1 Database Architect Administration A
John Doe 1234567 1 Database Tester Administration A
Use Distinct keyword
SELECT distinct c.FirstName+ ' ' + c.LastName as emp_full_name, e.EmployeeNumber,
e.EmpID, STUFF((
SELECT ',' + edh.PositionTitle
FROM dbo.EmployeeDepartmentHistory edh
WHERE edh.EmpID = e.EmpID
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, ''), e.isActive
FROM Person.Contact c
INNER JOIN HumanResources.Employee e ON c.ContactID = e.ContactID
INNER JOIN HumanResources.EmployeeDepartmentHistory dh ON e.EmpID = dh.EmpID
INNER JOIN HumanResources.Department d ON dh.DepartmentID = d.DepartmentID
WHERE c.FirstName+ ' ' + c.LastName LIKE #empName
Group By e.EmpID

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

SQL join related question

I am having trouble with a SQL join question.
I have a table EMPLOYEE with EmpID, FirstName, LastName, Email, Phone
I have another table OTHERNAME with 2 fields "Name" & "OtherName".
This table contains lookup values such as "James", "Jim"; "Thomas", "Tom"; "Steven", "Steve".
I want to write a query which will return rows
EmpID, FirstName, LastName, Email, Phone, OtherName
where Employee.Firstname = OTHERName.Name
Select e.EmpID, e.FirstName, e.LastName, e.Email, e.Phone, o.OtherName
From Employee e
Left Outer Join OtherName o on e.FirstName = o.Name
From your comments it sounds like you actually want an outer join.
(From Comments) An outer join would return all employees, along with an Othername if there is one, otherwise Othername would be a null value which you could handle in code. An inner join limits the results to only employees with a matching record.
try this:
SELECT
e.EmpID
CASE
WHEN o.OtherName IS NOT NULL THEN OtherName
ELSE e.FirstName
END AS FirstName
,e.LastName
,e.Email
,e.Phone
,o.OtherName
FROM Employee e
LEFT OUTER JOIN OtherName o ON e.FirstName = o.Name
select e.EmpID, e.FirstName, e.LastName, e.Email, e.Phone, o.OtherName
from employee e,othername o
where e.FirstName=o.name
SELECT E.EmpId,
E.FirstName,
E.LastName,
E.Email,
E.Phone,
O.OtherName
FROM EMPLOYEE E
INNER JOIN OTHERNAME O
ON E.FirstName = O.Name
SELECT E.EmpID, E.FirstName, E.LastName, E.Email, E.Phone, O.OtherName
FROM Employee E
INNER JOIN Othername O
ON E.Firstname = O.Name
Should do the trick
Or, if you want all results, even those without "other name" values.
SELECT E.EmpID, E.FirstName, E.LastName, E.Email, E.Phone, O.OtherName
FROM Employee E
LEFT OUTER JOIN Othername O
ON E.Firstname = O.Name
You may use following SQL Command
SELECT EMPLOYEE.EmpID,
EMPLOYEE.FirstName,
EMPLOYEE.LastName,
EMPLOYEE.Email,
EMPLOYEE.Phone,
OTHERNAME.OtherName FROM EMPLOYEE INNER JOIN OTHERNAME ON EMPLOYEE.FirstName = OTHERNAME.Name