I have the following table.
---------------------------------------------
check_id | action_id | user_id | dt |
---------------------------------------------
1 | 1 | 6 | 2011-09-17 |
2 | 1 | 6 | 2011-09-18 |
3 | 3 | 6 | 2011-09-19 |
4 | 3 | 6 | 2011-09-20 |
---------------------------------------------
I would like to query this table and get the following result.
-----------------------------------------------
action_id | user_id | dt_start | dt_end |
-----------------------------------------------
1 | 6 | 2011-09-17 | 2011-09-18 |
3 | 6 | 2011-09-19 | 2011-09-20 |
-----------------------------------------------
So I’m using the following query.
$checks->select()
->from(array('c1' => 'checks'), array('dt as dt_start')
->joinLeft(array('c2' => 'checks'), 'c1.action_id = c2.action_id', array('dt as dt_end')
->where('c1.user_id = ?', $userId)
->group('c1.action_id')
But this gives me the following result.
-----------------------------------------------
action_id | user_id | dt_start | dt_end |
-----------------------------------------------
1 | 1 | 2011-09-17 | 2011-09-17 |
1 | 3 | 2011-09-19 | 2011-09-19 |
-----------------------------------------------
Can someone tell me what I am doing wrong?
Try this query, without the group by:
You’ll see that you get matches where c1.dt < c2.dt, which is what you want.
But you also get matches where c1.dt > c2.dt, and where c1.dt = c2.dt.
That is, the self-join includes results where c1 and c2 point the very same row.
Then you use a GROUP BY that collapses multiple rows into one, but MySQL chooses an arbitrary row from the group. (This is an ambiguous query, and if you
SET SQL_MODE='ONLY_FULL_GROUP_BY'you’d get an error.)So your self-join and GROUP BY only returns c1 and c2 that are actually the very same row.
To fix this, you should add a condition that c1.dt < c2.dt.
You probably don’t need the GROUP BY at all in that case, assuming that you don’t have multiple starts and ends for each action.
By the way, this type of complexity is one reason that it’s usually recommended to store event start/end data in a single row, with the start in one column and the end in a second column.