views:

95

answers:

3

Getting this error: Each GROUP BY expression must contain at least one column that is not an outer reference.

RowId   ErrorDatetime             ErrorNum         ErrorMessage 
824 2010-09-24 08:01:42.000   9001       Account 55 not found
823 2010-09-24 08:00:56.000   9001      Account 22222222222 not found
822 2010-09-24 05:06:27.000   9001      Account 55 not found
821 2010-09-24 05:05:42.000   9001      Account 22222222222 not found

I'm trying to get the errormessage, and the first time it occurred for the current day, and that's working because I just do "Group by ErrorMessage".

However, if I want to find the first for each day:

SELECT Min(ErrorDateTime) as 'ErrorDateTime', Min(ErrorMessage) as 'ErrorMessage'
FROM CommonError 
WHERE dbo.StripTimeFromDate(ErrorDateTime) = dbo.StripTimeFromDate(getdate()) 
     and ErrorNumber = '9001' 
GROUP BY dbo.StripTimeFromDate(getdate()), ErrorMessage 

The handy-dandy function (from http://bloggingabout.net/blogs/jschreuder/archive/2007/03/13/useful-t-sql-date-functions.aspx):

ALTER FUNCTION [dbo].[StripTimeFromDate] (@inputDate DATETIME)
RETURNS DATETIME
BEGIN
    RETURN DATEADD(d, DATEDIFF(d, 0, @inputDate), 0)
END
+2  A: 

First, you don't need the MIN(ErrorMessage) in your SELECT. Simply SELECT ErrorMessage. Second, GROUP BY ErrorMessage only.

SELECT Min(ErrorDateTime) as 'ErrorDateTime', ErrorMessage
FROM CommonError 
WHERE dbo.StripTimeFromDate(ErrorDateTime) = dbo.StripTimeFromDate(getdate()) 
     and ErrorNumber = '9001' 
GROUP BY ErrorMessage 
Joe Stefanelli
I thought I said that was working, but then I said "However, if I want to find the first for each day"...
NealWalters
I misunderstood the requirements then. +1 to [OMG Ponies answer](http://stackoverflow.com/questions/3789487/sql-query-each-group-by-expression-must-contain-at-least-one-column-that-is-not/3789593#3789593) in that case.
Joe Stefanelli
I see the problem now, I had getdate() instead of ErrorDate in the group by.
NealWalters
+2  A: 

Use:

  SELECT t.errormessage, MIN(t.errordatetime) AS dt
    FROM COMMONERROR t
GROUP BY t.errormessage, DATEADD(d, DATEDIFF(d, 0, t.errordatetime), 0)

Check the references in the GROUP BY; it wasn't getting caught because MIN was being applied to the same column.

Assuming SQL Server 2005+, this is easier to handle with analytics:

WITH base AS (
   SELECT t.*,
          ROW_NUMBER() OVER(PARTITION BY t.errormessage, DATEADD(d, DATEDIFF(d, 0, t.errordatetime), 0)
                                ORDER BY t.errordatetime) AS rk
     FROM dbo.COMMONERROR t)
SELECT b.*
  FROM base b
 WHERE b.rk = 1
   AND b.errornumber = '9001' 
   AND DATEADD(d, DATEDIFF(d, 0, b.errordatetime), 0) = DATEADD(d, DATEDIFF(d, 0, GETDATE()), 0)
OMG Ponies
Works good (even when I take out the test for current date). However, I must admit, I have studied analytics enough to understand it. I was hoping to stick with my simple query and just get rid of the error. Not sure why it refers to "outer reference".
NealWalters
+1  A: 

I had getdate() instead of ErrorDate in the "group by". I think I saw similar issues in other forums where people had a literal in the "group by".

Correction is:

GROUP BY dbo.StripTimeFromDate(ErrorDate), ErrorMessage 
NealWalters