Помогите с алгоритмом (задача повышенной трудности))

S
На сайте с 03.07.2009
Offline
41
555

Ребята помогите пожалуйста с алгоритмом, уже вторые сутки лоб морщу, но эффективного алгоритма придумать не могу.

Исходные данные.

есть таблица с играми футбола

match

`id` int(11) счетчик

projectteam1_id int(11) Это код команды №1

projectteam2_id int(11) Это код команды №2

match_date datetime дата игры

и таблица с дисквалификациями игроков

match_discv

`id` int(11) счетчик

`match_id` int(11) id матча где был дисквалифицирован игрок

`projectteam_id` int(11) id команды где играл игрок

`teamplayer_id` int(11) id игрока

`srok` int(11) срок дисквалификации (количество пропускаемых игр)

Задача сделать выборку игроков имеющих неснятую дисквалификацию на текущее число.

Дисквалификация снимается с игрока после того как его команда сыграет то число матчей на которое он отстранен обычно отстраняют на 1 игру, но бывает что и на 4 игры.

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

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

Заранее благодарен за помощь

Кодинг на PHP. Разработка расширений под Joomla.
B
На сайте с 18.03.2008
Offline
47
#1

как-то так..

select match_discv.teamplayer_id

from match, match_discv

where match.id > match_discv.match_id

and match_discv.projectteam_id in (match.projectteam1_id,match.projectteam2_id)

group by match_discv.teamplayer_id, match_discv.srok

having count(match.id) < match_discv.srok

---------- Добавлено 18.03.2013 в 17:10 ----------

в группировку match_discv.`id` нужно добавить , чтобы повторные дисквалификации хорошо обрабатывались

---------- Добавлено 18.03.2013 в 17:11 ----------

т.е. так:

select match_discv.teamplayer_id

from match, match_discv

where match.id > match_discv.match_id

and (match_discv.projectteam_id = match.projectteam1_id

or

match_discv.projectteam_id = match.projectteam2_id)

group by match_discv.id, match_discv.teamplayer_id, match_discv.srok,

having count(match.id) < match_discv.srok

---------- Добавлено 18.03.2013 в 17:12 ----------

:) т.е.

так

select match_discv.teamplayer_id

from match, match_discv

where match.id > match_discv.match_id

and match_discv.projectteam_id in (match.projectteam1_id,match.projectteam2_id)

group by match_discv.id, match_discv.teamplayer_id, match_discv.srok

having count(match.id) < match_discv.srok

[umka]
На сайте с 25.05.2008
Offline
456
#2

Гораздо проще будет, если из колонки "srok" после каждого матча вычитать 1.

Лог в помощь!
B
На сайте с 18.03.2008
Offline
47
#3

Смотря какая задача.

Если вычитать, то нельзя будет сказать, что на момент игры год назад игроку оставалось пропустить N матчей.

S
На сайте с 03.07.2009
Offline
41
#4
select match_discv.teamplayer_id
from match, match_discv
where match.id > match_discv.match_id
and match_discv.projectteam_id in (match.projectteam1_id,match.projectteam2_id)
group by match_discv.id, match_discv.teamplayer_id, match_discv.srok
having count(match.id) < match_discv.srok

Не пойму как в условия включить сегодняшнее число.

Гораздо проще будет, если из колонки "srok" после каждого матча вычитать 1.

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

[umka]
На сайте с 25.05.2008
Offline
456
#5

Ну тогда другой способ, чтобы не насиловать базу данных пятиэтажными запросами с having-ами.

В таблицу match_discv добавляете поля:

date_start

date_finish

srok_rest

Когда в эту таблицу заносится игрок, то в date_start заносится дата дисквалификации, date_finish пустая, srok_left равно srok.

После каждого матча команды из srok_left вычитается 1.

Когда там остаётся 0 (т.е. пропущено нужное количество матчей), в date_finish заносится дата снятия дисквалификации.

Таким образом, для каждой дисквалификации каждого дисквалифицированного игрока появляется дата начала и дата завершения, и поставленная задача (выбрать игроков, имеющих дисквалификацию на произвольную дату) решается.

B
На сайте с 18.03.2008
Offline
47
#6

select match_discv.teamplayer_id

from match, match_discv

where match.id > match_discv.match_id

and match.match_date <= сегодня

and match_discv.projectteam_id in (match.projectteam1_id,match.projectteam2_id)

group by match_discv.id, match_discv.teamplayer_id, match_discv.srok

having count(match.id) < match_discv.srok

S
На сайте с 03.07.2009
Offline
41
#7

select match_discv.teamplayer_id

from match, match_discv
where match.id > match_discv.match_id
and match_discv.projectteam_id in (match.projectteam1_id,match.projectteam2_id)
group by match_discv.id, match_discv.teamplayer_id, match_discv.srok
having count(match.id) < match_discv.srok

всегда 0 строк выбирает, даже когда игроку в последнем матче дисквалификацию ставлю.

doctorpc
На сайте с 12.07.2009
Offline
112
#8

Попробуйте такой вариант:


SELECT A.teamplayer_id, A.srok, B.match_date,
( SELECT COUNT(*)
FROM `match` A1
WHERE A1.match_date > B.match_date
AND A1.match_date < NOW()
AND A.projectteam_id in(A1.projectteam1_id, A1.projectteam2_id)
) as matches_after_count

FROM `match_discv` A LEFT JOIN `match` B ON A.match_id=B.id
WHERE B.match_date < NOW()
HAVING matches_after_count < A.srok

Вместо NOW() лучше использовать конкретную дату, т.к. с NOW() некоторые индексы могут не работать.

S
На сайте с 03.07.2009
Offline
41
#9


SELECT A.teamplayer_id, A.srok, B.match_date,
( SELECT COUNT(*)
FROM `match` A1
WHERE A1.match_date > B.match_date
AND A1.match_date < NOW()
AND A.projectteam_id in(A1.projectteam1_id, A1.projectteam2_id)
) as matches_after_count

FROM `match_discv` A LEFT JOIN `match` B ON A.match_id=B.id
WHERE B.match_date < NOW()
HAVING matches_after_count < A.srok

Благодарю. запрос рабочий, нужно его хорошо протестировать.

Благодарю всех отписавшихся в этой теме.

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий