Reputation: 47
I am trying to write a query that will return the number of "proactive call cases" made by each employee per month as well as the total number of all cases. Essentially, I am looking to return 3 columns; an EmployeeName, a count of the Proactive Calls for that month, and a count of the total calls that month. To try and accomplish this I used a subquery. Here is what I have so far:
Select OpenedByName AS EmployeeName, Count(OpenedByName) As NumberOfProactiveCallsMONTH,
(Select Count(OpenedByName)
From table1
Where OpenDate Between '2/1/2014' and '3/1/2014' Group By OpenedByName) AS
TotalTicketsMONTH
From table1
Where OpenDate Between '2/1/2014' and '3/1/2014' AND ProblemType = 17
Group By OpenedByName
After running the query I got the error saying that:
"Msg 512, Level 16, State 1, Procedure SalesMTDSubQuery, Line 7 Subquery returned
more than 1 value. This is not permitted when the subquery follows =, !=, <, <= ,
>, >= or when the subquery is used as an expression."
I think it returned this error due to the GroupBy statement that I added in the subquery. When I remove the GroupBy it will just return the same value for every employee. I'm fairly new to using SQL so I'm not really sure of a good way around this. Any help would be much appreciated.
Thanks!
Upvotes: 1
Views: 5557
Reputation: 69819
You need to put a relation from the inner query to the outer query:
SELECT t1.OpenedByName AS EmployeeName,
COUNT(t1.OpenedByName) As NumberOfProactiveCallsMONTH,
( SELECT COUNT(OpenedByName)
FROM table1 t2
WHERE t2.OpenDate BETWEEN '2/1/2014' AND '3/1/2014'
AND t1.OpenedByName = t2.OpenedByName
) AS TotalTicketsMONTH
FROM table1 t1
WHERE t1.OpenDate BETWEEN '2/1/2014' AND '3/1/2014'
AND t1.ProblemType = 17
GROUP BY t1.OpenedByName;
However you can simplify the query by using a conditional aggregate (i.e. only counting when additional criteria is met):
SELECT t1.OpenedByName AS EmployeeName,
COUNT(CASE WHEN t1.ProblemType = 17 THEN t1.OpenedByName END) As NumberOfProactiveCallsMONTH,
COUNT(t1.OpenedByName) As TotalTicketsMONTH
FROM table1 t1
WHERE t1.OpenDate BETWEEN '2/1/2014' AND '3/1/2014'
GROUP BY t1.OpenedByName;
The next improvement would be to change your date format to one that not culture specific - is 2/1/2014
2nd January or 1st February? If you use yyyyMMdd
there is no ambiguity.
Finally, your query will include tickets opened on 1st March at midnight, I suspect these should not be included in February's data, you would be better of using >=
and `<'. Making your final query:
SELECT t1.OpenedByName AS EmployeeName,
COUNT(CASE WHEN t1.ProblemType = 17 THEN t1.OpenedByName END) As NumberOfProactiveCallsMONTH,
COUNT(t1.OpenedByName) As TotalTicketsMONTH
FROM table1 t1
WHERE t1.OpenDate >= '20140201'
AND t1.OpenDate < '2014031'
GROUP BY t1.OpenedByName;
For further reading on Date range queries:
Upvotes: 0
Reputation: 34784
You need to relate the sub-select to the outer statement, otherwise, as you noticed, you return multiple lines in the sub-select which doesn't work.
SELECT OpenedByName AS EmployeeName
, COUNT(OpenedByName) AS NumberOfProactiveCallsMONTH
, ( SELECT COUNT(OpenedByName)
FROM table1 b
WHERE OpenDate BETWEEN '2/1/2014' AND '3/1/2014'
AND b.OpenedByName = a.OpenedByName
GROUP BY OpenedByName
) AS TotalTicketsMONTH
FROM table1 a
WHERE OpenDate BETWEEN '2/1/2014' AND '3/1/2014'
AND ProblemType = 17
GROUP BY OpenedByName
But you can greatly simplify this by using a conditional sum instead of a sub-select:
SELECT OpenedByName AS EmployeeName
, SUM(ProblemType = 17) NumberOfProactiveCallsMONTH
, COUNT(OpenedByName) AS TotalTicketsMONTH
FROM table1
WHERE OpenDate BETWEEN '2/1/2014' AND '3/1/2014'
GROUP BY OpenedByName
Upvotes: 0
Reputation: 2898
You can use like this
Select a.OpenedByName AS EmployeeName, Count(a.OpenedByName) As NumberOfProactiveCallsMONTH,
b.TotalTicketsMONTH AS TotalTicketsMONTH
From table1 a
INNER JOIN
(Select OpenedByName ,Count(OpenedByName) AS TotalTicketsMONTH From table1
Where OpenDate Between '2/1/2014' and '3/1/2014' Group By OpenedByName) b ON
a.OpenedByName = b.OpenedByName
Where a.OpenDate Between '2/1/2014' and '3/1/2014' AND a.ProblemType = 17
Group By a.OpenedByName
Upvotes: 0
Reputation: 166606
How about something like
SELECT OpenedByName AS EmployeeName,
SUM(CASE WHEN ProblemType = 17 THEN 1 ELSE 0 END) AS NumberOfProactiveCallsMONTH,
COUNT(1) TotalTicketsMONTH
FROM Table1
Where OpenDate Between '2/1/2014' and '3/1/2014'
GROUP BY OpenedByName
The error you received was due to the fact that when using a sub query as a column, it cannot return more than 1 value.
Now the way you had it structured, it would have returned all the COUNT
values per OpenedByName, instead of a single value per OpenedBy.
If you realy wish to use your quer, you need to limit the lookup in the column select to the actual OpenedByName. So something like
Select OpenedByName AS EmployeeName, Count(OpenedByName) As NumberOfProactiveCallsMONTH,
(Select Count(OpenedByName)
From table1 t
Where OpenDate Between '2/1/2014' and '3/1/2014'
AND t.OpenedByName = t1.OpenedByName) AS
TotalTicketsMONTH
From table1 t1
Where OpenDate Between '2/1/2014' and '3/1/2014' AND ProblemType = 17
Group By OpenedByName
Upvotes: 1