Nomi Khurram Nomi Khurram - 5 months ago 11
SQL Question

How to use SQL Case in Group by Clause?

I'm using SQL Case in my select and in group by clause and I'm working in JAVA. Whenever I execute my java program it says:


Column 'dbo.JOHN_Dashboard.Log_Date' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.


My Query is:

SELECT EP.Site_Code AS [Site_Code], DB.[Site] AS [Site], DB.[Utility] AS [Utility],
CASE ? WHEN 'Raw' THEN dateadd(mi,datediff(mi,0,DB.[log_date]),0)
WHEN 'Hour' THEN dateadd(hh,datediff(hh,0,DB.[log_date]),0)
WHEN 'Day' THEN dateadd(dd,datediff(dd,0,DB.[log_date]),0)
WHEN 'Week' THEN dateadd(wk,datediff(wk,0,DB.[log_date]),0)
WHEN 'Month' THEN dateadd(mm,datediff(mm,0,DB.[log_date]),0)
WHEN 'Year' THEN dateadd(yy,datediff(yy,0,DB.[log_date]),0)
ELSE DB.[log_date]
END AS [log_date],
SUM(CASE WHEN DB.[value] >= 0 THEN DB.[value] ELSE 0 END) AS [value],
SUM(CASE WHEN DB.[Cost] >=0 THEN DB.[cost] ELSE 0 END) AS [Cost],
SUM(CASE WHEN DB.[CO2] >=0 THEN DB.[CO2] ELSE 0 END) AS [CO],
MT.[Meter_type_name] AS [Meter Type],
MN.[Meter_Name] AS [Meter Name],
U.[Unit_Name] AS [Units],
EP.EnergyPoint_ID AS [Meter_ID],
EP.Parent_ID AS [Parent],
EP.Meter_Description AS [Meter_Description]
FROM [dbo].[JOHN_Dashboard] DB
INNER JOIN [dbo].[EnergyPoints] EP ON DB.[EnergyPoint_ID] = EP.[EnergyPoint_ID]
INNER JOIN [dbo].[Meter_Types] MT ON MT.[Meter_Type_ID] = EP.[Meter_Type_ID]
INNER JOIN [dbo].[Meter_Names] MN ON MN.[Meter_Name_ID] = EP.[Meter_Name_ID]
INNER JOIN [dbo].[Units] U ON U.[Unit_ID] = EP.[Unit_id]
WHERE [log_date] >= ? AND [Log_Date] < DATEADD(DAY, 1, ?)
AND ( ? IS NULL OR EP.Energypoint_ID = ?)
GROUP BY EP.Site_Code, DB.[Site], DB.[Utility], MT.[Meter_type_name],
MN.[Meter_Name], U.[Unit_Name], EP.[EnergyPoint_ID],
EP.[Parent_ID], EP.[Meter_Description],
CASE ? WHEN 'Raw' THEN dateadd(mi,datediff(mi,0,DB.[log_date]),0)
WHEN 'Hour' THEN dateadd(hh,datediff(hh,0,DB.[log_date]),0)
WHEN 'Day' THEN dateadd(dd,datediff(dd,0,DB.[log_date]),0)
WHEN 'Week' THEN dateadd(wk,datediff(wk,0,DB.[log_date]),0)
WHEN 'Month' THEN dateadd(mm,datediff(mm,0,DB.[log_date]),0)
WHEN 'Year' THEN dateadd(yy,datediff(yy,0,DB.[log_date]),0)
ELSE DB.[log_date] END ;


The parameters i'm passing are:


  1. 'Week'

  2. '2016-05-16'

  3. '2016-05-22'

  4. 6044

  5. 6044

  6. 'Week'



Note: This query runs without error in SQL Management Studio.

SMM SMM
Answer

As requested here is a reworked version of your code using a sub-query before grouping. Since I don't have your database I can't guarantee that I have everything exactly right but give this a try.

I recommend always using a sub-query when your group by has complicated logic that will be repeated in the select. Some people would probably drop the second criteria and just say whenever the group by has complicated logic.

SELECT  sub.Site_Code, sub.[Site], sub.[Utility], sub.[Meter Type],
        sub.[log_date],
        SUM(sub.[value]) as [value],
        SUM(sub.[Cost]) as [cost],
        SUM(sub.[CO]) as [CO],
        sub.[Meter Name], sub.[Units], sub.[Meter_ID],
        sub.[Parent], sub.[Meter_Description]
FROM    (
        SELECT EP.Site_Code AS [Site_Code], DB.[Site] AS [Site], DB.[Utility] AS [Utility], 
                CASE ? WHEN 'Raw' THEN dateadd(mi,datediff(mi,0,DB.[log_date]),0) 
                WHEN 'Hour'  THEN dateadd(hh,datediff(hh,0,DB.[log_date]),0)
                WHEN 'Day'   THEN dateadd(dd,datediff(dd,0,DB.[log_date]),0)
                WHEN 'Week'  THEN dateadd(wk,datediff(wk,0,DB.[log_date]),0)
                WHEN 'Month' THEN dateadd(mm,datediff(mm,0,DB.[log_date]),0)
                WHEN 'Year'  THEN dateadd(yy,datediff(yy,0,DB.[log_date]),0)                                                     
                ELSE DB.[log_date]
                END AS [log_date],
                CASE WHEN DB.[value] >= 0 THEN DB.[value] ELSE 0 END AS [value],
                CASE WHEN DB.[Cost] >=0 THEN DB.[cost] ELSE 0 END AS [Cost],
                CASE WHEN DB.[CO2] >=0 THEN DB.[CO2] ELSE 0 END AS [CO],
                MT.[Meter_type_name] AS [Meter Type],
                MN.[Meter_Name] AS [Meter Name],
                U.[Unit_Name] AS [Units],
                EP.EnergyPoint_ID AS [Meter_ID],
                EP.Parent_ID AS [Parent],
                EP.Meter_Description AS [Meter_Description] 
        FROM [dbo].[JOHN_Dashboard] DB
        INNER JOIN [dbo].[EnergyPoints] EP ON DB.[EnergyPoint_ID] = EP.[EnergyPoint_ID] 
        INNER JOIN [dbo].[Meter_Types] MT ON MT.[Meter_Type_ID] = EP.[Meter_Type_ID]
        INNER JOIN [dbo].[Meter_Names] MN ON MN.[Meter_Name_ID] = EP.[Meter_Name_ID]
        INNER JOIN [dbo].[Units] U ON U.[Unit_ID] = EP.[Unit_id]
        WHERE [log_date] >= ? AND [Log_Date] < DATEADD(DAY, 1, ?)
        AND ( ? IS NULL OR EP.Energypoint_ID = ?)
        ) sub
GROUP BY sub.Site_Code, sub.[Site], sub.[Utility], sub.[Meter Type],           
        sub.[Meter Name], sub.[Units], sub.[Meter_ID],
        sub.[Parent], sub.[Meter_Description], sub.[log_date];
Comments