views:

532

answers:

5

I am porting some queries from Access to T-SQL and those who wrote the queries used the Avg aggregate function on datetime columns. This is not supported in T-SQL and I can understand why - it doesn't make sense. What is getting averaged?

So I was about to start reverse engineering what Access does when it aggregates datetime using Avg, but thought I would throw the question out here first.

A: 

Well it is supported, please check this site and learn:

Link

MysticSlayer
AVG() is not supported with dates in T-SQL - only with numeric types.
Scott Ivey
+2  A: 

I'd imagine that Access is averaging the numeric representation of the dates. You could do similar in T-SQL with the following...

select AverageDate = cast(avg(cast(MyDateColumn as decimal(20, 10))) as datetime)
from    MyTable
Scott Ivey
Yes, thats what I assumed and it is probably the most logical thing. I was wondering if maybe it wasn't doing some kind of partitioning like the average time of day or something.
MarkB
A Jet date field is an integer value for the day plus a decimal value for the time. If you want to average only on the dates, use the integer value.
David-W-Fenton
MS SQL is similar - casting to int will give you just the average of the date portion
Scott Ivey
+1  A: 

I'm more familiar with non-MS DBMS, but... Since you cannot add two DATETIME values, you cannot ordinarily average them. However, you could do something similar to:

SELECT AVG(datetime_column - TIMESTAMP '2000-01-01 00:00:00.000000') +
              TIMESTAMP '2000-01-01 00:00:00.000000'
    FROM table_containing_datetime_column;

This calculates the average interval between the start of 2000 and the actual datetime values, and then adds that interval to the start of 2000. The choice of 'start of 2000' is arbitrary; as long as the datetime subtracted in the AVG() function is added back, you get a sensible answer.

This does assume that the DBMS used supports SQL standard 'timestamp' notation, and supports the INTERVAL types appropriately. The difference between two DATETIME or TIMESTAMP values should be an INTERVAL (indeed, INTERVAL DAY(9) TO SECOND(6), to be moderately accurate, though the '9' is somewhat debatable).

When appropriately mangled for the DBMS I work with, the expression 'works':

CREATE TEMP TABLE table_containing_datetime_column
(
    datetime_column DATETIME YEAR TO FRACTION(5) NOT NULL
);

INSERT INTO table_containing_datetime_column VALUES('2008-11-19 12:12:12.00000');
INSERT INTO table_containing_datetime_column VALUES('2008-11-19 22:22:22.00000');

SELECT AVG(datetime_column - DATETIME(2000-01-01 00:00:00.00000) YEAR TO FRACTION(5)) +
    DATETIME(2000-01-01 00:00:00.00000) YEAR TO FRACTION(5)
FROM table_containing_datetime_column;

Answer:

2008-11-19 17:17:17.00000
Jonathan Leffler
A: 

here you can find what you want. http://www.cnblogs.com/ITGIS/articles/1501306.html

A: 

@David W. Fenton: "A Jet date field is an integer value for the day plus a decimal value for the time" -- no, an ACE/Jet DATETIME column is a FLOAT (synonyms DOUBLE, FLOAT8, IEEEDOUBLE, NUMBER) with limits e.g. the maximum DATETIME value is #9999-12-31:23:59:59# though the maximum FLOAT value that can be cast to DATETIME will be a little larger e.g.

SELECT CDBL(CDATE('9999-12-31 23:59:59'))

returns 2958465.99998843, however

SELECT CDATE(CDBL(2958465.9999999997))

does not error, whereas

SELECT CDATE(CDBL(2958465.9999999998))

does error.

Therefore, to preserve functionality in SQL Server, I suggest casting the DATETIME column to FLOAT e.g.

SELECT CAST(AVG(CAST(MyDateTimeColumn AS FLOAT)) AS DATETIME)
  from MyTable
onedaywhen