Выборка с предыдущей записью

teleman

Новичок
Есть загвоздка.
Таблица с телепрограммой. Поля time(TADETIME), chid(INT), text(CHAR). (соответственно, время начала, ид канала, и собственно название передачи. Около 300 каналов.
Понадобилось сделать выборку для каждого канала текущей передачи, +3 последующих.
Как сделать ума не приложу.
Вариант типа:
SELECT * FROM programm WHERE time > (NOW() - INTERVAL 2 hour) AND time < (NOW() + INTERVAL 2 hour
пришлось отбросить сходу, поскольку продолжительность программы варьируется от 2 минут до 3 часов
вариант:
(SELECT * FROM programm
WHERE time < NOW() AND chid = '".$chid."'
ORDER BY time DESC LIMIT 1)
UNION
(SELECT *FROM programm
WHERE time > NOW() AND chid = '".$chid."'
ORDER BY time ASC LIMIT 3)
ORDER BY time
работает, но, блин он актуален для каждого канала, и делать перебор запросов, считаю неверным решением. Тем более, что запрос сам по себе по времени очень тормозит.
Гуру, посоветуйте в какую сторону рыть, поскольку своих идей пока нет.
 

WMix

герр M:)ller
Партнер клуба
можно за selfjoin'ить приблизительно так (не тестил)
Код:
SELECT p1.*, count(p2.*) as nr
FROM programm p1
JOIN programm p2 ON p1.child = p2.child AND p1.time <= p2.time
GROUP BY p1.child, p1.time
HAVING nr < 3
 

teleman

Новичок
ньюанс в том, нужно выбрать одну запись меньше текущего времени и остальные больше текущего.
попробую решить эту проблему на уровне сортировки массива
 

fixxxer

К.О.
Партнер клуба
Тут бы идеально подошли window functions, но раз mysql, придется страдать.

Как-то так, скажем:

PHP:
set @num := 0, @channel_id := 0;
select chid, ctime from (
	select pp.chid, pp.ctime,
	@num := if(@channel_id = pp.chid, @num + 1, 1) as row_number,
	@channel_id := pp.chid as _
	from (
		select p.chid, p.ctime
		from
		(
			select chid, max(ctime) as ctime from programm
			where ctime < now()
			group by chid
		) lp
		join programm p on (p.chid = lp.chid and p.ctime >= lp.ctime)
                # тут имеет смысл добавить условие на максимальное время, превышающее любое разумное
		order by chid, ctime
	) pp
) ppp where ppp.row_number<=3;
 

fixxxer

К.О.
Партнер клуба
@WMix, ему надо не остальные, а +3, и вроде как для всех каналов сразу. это все усложняет
 

WMix

герр M:)ller
Партнер клуба
разве? запрос перезакрученый, но сложить можно вроде
 

WMix

герр M:)ller
Партнер клуба
чтот в этом роде
Код:
SELECT p1.*, count(distinct p2.*) as nr, count(distinct p3.*) as nr2
FROM programm p1
JOIN programm p2 ON p1.child = p2.child AND p1.time <= p2.time
JOIN programm p3 ON p1.child = p3.child AND p1.time > p3.time
GROUP BY p1.child, p1.time
HAVING nr < 3 and nr2 < 1
 

fixxxer

К.О.
Партнер клуба
а почему nr2<1?

ход мысли понял, да, вроде должно с тремя джойнами получиться
 

teleman

Новичок
разобрать массив показало более интересные значения по времени. Спасибо, всем откликнувшимся.
 

fixxxer

К.О.
Партнер клуба
ну логично в принципе, window functions это и есть тот самый разбор, только на лету во время чтения из таблицы. Думаю, оптимальнее всего будет выполнить запрос типа

PHP:
        select p.chid, p.ctime
        from
        (
            select chid, max(ctime) as ctime from programm
            where ctime < now()
            group by chid
        ) lp
        join programm p on (p.chid = lp.chid and p.ctime >= lp.ctime)
        order by p.ctime # ну или p.chid, p.ctime - на что у тебя там индекс есть
и дополнительно отфильтровать-сгруппировать по ходу вычитывания результата, эмулируя window functions на уровне php.
 

teleman

Новичок
обнаружился риф, разбивающий хорошую идею. Часть каналов мертвые (невидимая рука рынка), по ним, соответственно, выбрались строки, описывающие их бесславное прошлое. База программы за десяток лет и печальный итог: Запрос занял 32.3517 сек
Это по индексированному полю.
Увы, идея только одним запросом решить задачу оказалась невыполнима. Выборка временного интервала в массив с сортировкой массива т.е. sql+php работает шустро, хотя выглядит как костыль.
Спасибо за желание помочь. У вас на форуме есть чему и у кого поучиться. Спасибо.
 
Сверху