Просто на подумать:
Основная проблема в том, что ночная смена начинается одним днем, заканчивается другим.
Поэтому надо проанализировать время и если больше 22 часов - то это ночная смена + рабочий день = следующий, т.е. добавить день. Или наоборот если < 10 утра, то это ночная предыдущего - то -1 день.
анализируем данные, добавляя (или убирая день для ночных) - получаем рабочий день, + признак day или night
группируем уже по полученному рабочему дню, смене, кассиру.
SELECT S.workday, S.smena, S.userid, COUNT(*)
FROM (
SELECT t.dtime, t.userid,
CONVERT( CASE WHEN HOUR(t.dtime) >= 22 THEN DATE_ADD(t.dtime,INTERVAL 1 DAY) ELSE t.dtime END, DATE) as 'workday',
CASE WHEN HOUR(t.dtime) >= 10 AND HOUR(t.dtime) < 22 THEN 'day' ELSE 'night' END as 'smena'
FROM test AS t
) S
GROUP BY workday, smena, userid
ORDER BY S.workday ASC, S.smena DESC, S.userid
пример тут:
sqlfiddle.com/#!9/7bd4f/4/0
НО. есть одно большое НО.
Кассиры начинают или заканчивают работы не ровно в 10 утра или 22 вечера.
В вашем же примере
10.10.2015 9:51; 514; 3000
по идее он попадает в ночную смену по интервалу времени, а в реальности работник начал работать раньше.
Либо вводить признак день\ночь и уже не опираться на время либо придумывать велосипед.