0

Is there a way to not duplicate the group by clause when it is included in the select?

For example, one can do:
Select x,y,z from mytable order  by 1,2,3
If the clauses of x,y, and z are long complicated functions, this saves typing and mistakes.
However, I am not aware of a typing saver for:
Select f(x),g(y),avg(z) from MyTable group by f(x),g(y)

Any ideas?

Larger example:

SELECT 
     DATEADD(HOUR,datepart(hour,inquirydate),cast(cast(inquirydate as date) as datetime)) as dayhour,
     COUNT(*) as qty,
     AVG(workms+queuems+0.0) as avgTimeMs
    FROM datalog 
  WHERE inquirydate>'1/1/2014'
  GROUP BY DATEADD(HOUR,datepart(hour,inquirydate),cast(cast(inquirydate as date) as datetime))

Notice a large chunk of the above was repeated. When one repeats oneself, they tend to make mistakes.

Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786
Chris
  • 1,219
  • 2
  • 11
  • 21

2 Answers2

0

1) Use a User defined function if this is a common calculation
OR
2) As Aaron Bertrand suggested wrap it in a subquery

dev_b_459821
  • 41
  • 1
  • 1
  • 3
0

As mentioned, there are few methods: subquery, CTE and OUTER APPLY:

-- Solution #1: subquery

SELECT 
    h.dayhour,
    COUNT(*) as qty,
    AVG(workms+queuems+0.0) as avgTimeMs
FROM (
    SELECT 
        DATEADD(HOUR,datepart(hour,inquirydate),cast(cast(inquirydate as date) as datetime)) as dayhour,
        workms, queuems
    FROM    datalog 
    WHERE   inquirydate>'20140101' -- It's better to use a date literal (DDMMYYY for DATETIME, DD-MM-YYYY for DATE) which is independent of DATEFORMAT / LANGUAGE settings
) h -- hours subquery
GROUP BY h.dayhour;

-- Solution #2: Common Table Expression

;WITH CteHours
AS (
    SELECT 
        DATEADD(HOUR,datepart(hour,inquirydate),cast(cast(inquirydate as date) as datetime)) as dayhour,
        workms, queuems
    FROM    datalog 
    WHERE   inquirydate>'20140101' 
)
SELECT h.dayhour,
    COUNT(*) as qty,
    AVG(workms+queuems+0.0) as avgTimeMs
FROM CteHours h -- hours subquery
GROUP BY h.dayhour;

-- Solution #2: OUTER APPLY

SELECT 
    expr.dayhour, 
    COUNT(*) as qty,
    AVG(workms+queuems+0.0) as avgTimeMs
FROM    datalog d
OUTER APPLY (
    SELECT DATEADD(HOUR,datepart(hour,d.inquirydate),cast(cast(d.inquirydate as date) as datetime)) as dayhour
) AS expr
WHERE   inquirydate>'20140101' 
GROUP BY expr.dayhour;

Usually, I use solution #1 and, sometimes (when query is complex), solution #3.

Bogdan Sahlean
  • 19,233
  • 3
  • 42
  • 57
  • Bogdan Sahlean, the OUTER APPLY looks to be the most concise. Is that standard SQL? I wonder if it will work in PostgresSQL when I need to do that... – Chris Mar 26 '15 at 00:54
  • `OUTER/CROSS APPLY` is not included in SQL ANSI standard. According to [this answer](http://stackoverflow.com/questions/11472790/analogue-to-cross-apply) the equivalent of `OUTER APPLY` for `PostgreSQL` is `LATERAL JOIN`. – Bogdan Sahlean Mar 26 '15 at 04:42