views:

973

answers:

3

(sql server 2005)

A person uses their cell phone multiple times per day, and the length of their calls vary.

I am tracking the length of the calls in a table:

Table: Calls [callID, memberID, startTime, duration]

I need to a query to return the average call length for users PER DAY.

Per day means, if a user used the phone 3 times, first time for 5 minutes, second for 10 minutes and the last time for 7 minutes, the calculation is: 5 + 10 + 7 / 3 = ...

Note:

  1. People don't use the phone everyday, so we have to get the latest day's average per person and use this to get the overall average call duration.

  2. we don't want to count anyone twice in the average, so only 1 row per user will go into calculating the average daily call duration.

Update Some clarifications:

I want a overall per day average, based on the per-user per-day average, using the users latest days numbers (since we are only counting a given user ONCE in the query), so it will mean we will be using different days avg. since people might not use the phone each day or on the same day even.

A: 
select average(duration) from calls group by date(startTime);
matt b
date() is not a function on SQL Server.
Tomalak
The question was originally tagged mysql.
matt b
+1  A: 

You need to convert the DATETIME to something you can make "per day" groups on, so this would produce "yy/mm/dd".

SELECT
  memberId,
  CONVERT(VARCHAR, startTime, 102) Day,
  AVG(Duration) AvgDuration
FROM
  Calls
WHERE
  CONVERT(VARCHAR, startTime, 102) = 
  (
    SELECT 
      CONVERT(VARCHAR, MAX(startTime), 102) 
    FROM 
      Calls i WHERE i.memberId = Calls.memberId
  )
GROUP BY
   memberId,
   CONVERT(VARCHAR, startTime, 102)

Use LEFT(CONVERT(VARCHAR, startTime, 120), 10) to produce "yyyy-mm-dd".

For these kind of queries it would be helpful to have a dedicated "day only" column to avoid the whole conversion business and as a side effect make the query more readable.

Tomalak
it is returning multiple rows per member, I need the latest one only (just 1, and the latest one)
Anonymous Cow
Then you only need to group by the date field ( CONVERT(VARCHAR, startTime, 102) )
matt b
But then the "per member" average would go away as well.
Tomalak
There is a ayntax error in your query, as there is no table called member, AND it doesn't get the overall average as the user asked for.
Mitchel Sellers
Quote: "we have to get the latest day's average per person". I figured the poster is able to put a simple SELECT AVG around that. You are right, and there is no table called "member", good job. ;-)
Tomalak
Tomalak, thanks allot for your help! Bigtime!
Anonymous Cow
tomalak, you might want to modify your entry to correct the script error.
Mitchel Sellers
A: 

The following query will get you the desired end results.

SELECT AVG(rt.UserDuration) AS AveragePerDay
FROM
(
    SELECT
     c1.MemberId,
     AVG(c1.Duration) AS "UserDuration"
    FROM Calls c1
    WHERE CONVERT(VARCHAR, c1.StartTime, 102) =
     (SELECT CONVERT(VARCHAR, MAX(c2.StartTime), 102)
      FROM Calls c2
      WHERE c2.MemberId = c1.MemberId)
    GROUP By MemberId
) AS rt

THis accomplishes it by first creating a table with 1 record for each member and the average duration of their calls for the most recent day. Then it simply averages all of those values to get the end "average call duration. If you want to see a specific user, you can run just the innser SELECT section to get the member list

Mitchel Sellers
running the inner query (inside the from) returns: An aggregate may not appear in the WHERE clause unless it is in a subquery contained in a HAVING clause or a select list, and the column being aggregated is an outer reference.
Anonymous Cow
I just tested an you can run everything from the "SELECT c1.MemberId" town to the "Group BY MemberId" statement.
Mitchel Sellers
I hop that got what you needed!
Mitchel Sellers