views:

57

answers:

3

I have a table:

  id | score | date
 bob |    40 | 2010-1-1
 bob |    70 | 2010-1-15
 sue |    55 | 2010-1-1
 sue |    80 | 2010-2-1

I want to query for either the score for a user on a specific date OR, if no score exists for that user on that date,return the score from the most recent date for that user.

Is there a way to do this without a sub-query?

For instance, if I do:

SELECT score
FROM table
WHERE id = '$id'
AND IFNULL(
    date = DATE(FROM_UNIXTIME($date)),
    MAX(date)   
    )

I would get no result, as the id does not show up for the most recent date.

Update

Felix reminded me I can't use aggregate functions in the WHERE clause, so now I'm wondering if there is a pseudo-aggregate date function for saying "most recent date" in the where clause, and if so, if I can specify the user when using THAT function?

Update 2

So this is what I have gotten to work, but I still don't know if it's the best way to go (ie, do I need the nested query?):

SELECT score
FROM table
WHERE id = '$id'
AND date = IFNULL(
    (SELECT date FROM table
    WHERE id = '$id' AND
    date = DATE(FROM_UNIXTIME($date))
    ),
    (SELECT MAX(date) FROM table
    WHERE id = '$id'
    )
)
A: 

Use this query :

SELECT * FROM test
WHERE date = (
    SELECT MAX(date) FROM test
) ;

If you want based on the id , you need to do group by operation on id column

pavun_cool
+1  A: 
SELECT score
  FROM table
 WHERE id = '$id'
   AND date > '2010-01-01'
 ORDER BY date DESC
 LIMIT 1

EDIT

See my second comment regarding the interpretations:

Interpretation 1:

SELECT score
  FROM table
 WHERE id = '$id'
   AND date >= '2010-01-01'
 ORDER BY date ASC
 LIMIT 1

Interpretation 2:

SELECT score,
       LEAST(ABS(DATEDIFF('2010-01-01', date)), 1) AS myorder
  FROM table
 WHERE id = '$id'
   AND date >= '2010-01-01'
 ORDER BY myorder ASC, date DESC
 LIMIT 1
aefxx
This only works if I don't have another date condition to check for first, but otherwise this is pretty clever.
Anthony
No, this works with any possibly thinkable WHERE condition.
aefxx
I may be missing the magic to your solution, but what I need is a query that returns the needed value first based on the id and the given date, and if that id does not exist on that date, the most recent date available for that id. Your query seems to only work for the second condition. Am I missing something?
Anthony
Tell me what do you mean by "most recent date available"? I can think of two interpretations: 1. try to match the exact date // if not available retrieve the nearest possible date. OR 2. try to macht the exact date // if not available retrieve the record with the most recent date.
aefxx
The second interpretation. Basically if there is no row for that date, it means the user hasn't done something for that date, so we want to get the value they used on the row that has the most recent date. The idea is that the user is probably doing this in chronological order, so the most recent date is probably the last time they saved something, so we want to use the group key from the most recent post on the new post as they tend to skip over setting it correctly and it gets saved to the top choice in the drop down list and it screws up stuff. Thanks for all of your help!
Anthony
+1  A: 

Not sure of the performance of this one:

SELECT a.*
FROM table a
LEFT JOIN table b ON (
  b.date=DATE(FROM_UNIXTIME($date)) AND b.date=a.date AND b.id=a.id
)
WHERE a.id='$id'
ORDER BY b.date DESC, a.date DESC
LIMIT 1
Patrick
If the score/id exists for the `$date`, the left join goes into effect, right? and if no ID exists for that date, does the query still return the most recent row (newest date) available for that ID? I'm really close to being impressed, but I don't quite see what the query actually returns. I'm going to run it without the row limit to check. I'll be super amazed if this does the trick.
Anthony
If the date is found b.date will be not be null and since i m ordering first by b.date in reverse order the first line will be the date found otherwise it will be the a.date ordered in reverse order so the max date come first.
Patrick
Yeah, I was getting LEFT JOIN mixed up with INNER JOIN, I think. But either way, this worked and is awesome. My co-worker batted his eyes and said it was near-magic.
Anthony
Cool it works :)
Patrick