:: Игры Разума
Можно ли в этой задачке обойтись только реляционными командами?
Вячеслав Клепинин

Сообщений: 1597
Откуда: Санкт-Петербург
Дата регистрации: 26.03.2004
Что-то тихо здесь стало...
Вот ещё одна задачка, которую мне не удалось решить, используя только реляционные команды. Может, кто сумеет?

Мониторинг рекламы. В БД ведётся список рекламных модулей, опубликованных в прессе.
Существует выборка за определённый временной период вида:

modules(id_smi, id_org, smod, cena, data)

где: id_smi - ID газеты, в которой опубликована реклама; id_org - ID рекламодателя; smod - площадь модуля; cena - его стоимость; data - дата публикации.

Выбранный период разбит пополам, т.е. появляются предыдущий и текущий периоды; значение даты половины интервала задаётся в переменной.

Нужно получить результирующий курсор вида:

result(id_smi, org, delta_org, smod, delta_smod, mod, delta_mod, cena, delta_cena)

где по каждому СМИ:
org - количество рекламодателей за текущий период;
delta_org - изменение количества рекламодателей по отношению к предыдущему периоду;
smod - общая площадь рекламы за текущий период, delta_smod - изменение площади рекламы по отношению к предыдущему периоду;
mod - количество рекламных модулей за текущий период

Ну и так далее.



Исправлено 1 раз(а). Последнее : Вячеслав Клепинин, 22.03.07 11:42
Ratings: 0 negative/0 positive
Re: Можно ли в этой задачке обойтись только реляционными командами?
PaulWist

Сообщений: 14601
Дата регистрации: 01.04.2004
Слава, ну скрипт бы написал с заполнением таблички, что бы только select добавить надо было.


------------------
Есть многое на свете, друг Горацио...
Что и не снилось нашим мудрецам.
(В.Шекспир Гамлет)
Ratings: 0 negative/0 positive
Re: Можно ли в этой задачке обойтись только реляционными командами?
leonid

Сообщений: 3202
Откуда: Рига
Дата регистрации: 03.02.2006
Что-то в таком духе?
create cursor rekl (id_smi i, id_org i, smod N(4), cena N(6,2), data D)
rand(-1)
local m.i, m.mindat, m.maxdat, m.middat
m.mindat=date()-90
m.maxdat=date()
for i=1 to 1000
insert into rekl values ;
(rnd(1,5), rnd(1,100), rnd(30,300), rnd(200,2000)/100, ;
m.mindat+rnd(0,m.maxdat-m.mindat))
next
m.middat=m.mindat+45
select id_smi, count(distinct id_org) as orgp, ;
sum(smod) as smodp, sum(cena) as cenap from rekl ;
where data<=m.middat group by 1 into cursor tmp1
select id_smi, count(distinct id_org) as org, ;
sum(smod) as smod, sum(cena) as cena from rekl ;
where data>m.middat group by 1 into cursor tmp2
select nvl(t1.id_smi, t2.id_smi) as id_smi, ;
nvl(t2.org,00000) as org, ;
nvl(t2.org,00000)-nvl(t1.orgp,00000) as delta_org, ;
nvl(t2.smod,00000) as smod, ;
nvl(t2.smod,00000)-nvl(t1.smodp,00000) as delta_smod, ;
nvl(t2.cena,00000) as cena, ;
nvl(t2.cena,00000)-nvl(t1.cenap,00000) as delta_cena ;
from tmp1 t1 full outer join tmp2 t2 on t1.id_smi=t2.id_smi
function rnd
lparam m.imin, m.imax
return min(int(rand()*(m.imax-m.imin+1))+m.imin, m.imax)
Ratings: 0 negative/0 positive
Re: Можно ли в этой задачке обойтись только реляционными командами?
Вячеслав Клепинин

Сообщений: 1597
Откуда: Санкт-Петербург
Дата регистрации: 26.03.2004
leonid, спасибо!

Как-то не пришло в голову использовать full join. Я его практически по жизни использовал пару раз, не больше...
По времени выполнения разницу с моим кодом не поймать, так как результирующие курсоры очень маленькие.

Ещё раз спасибо! Пошёл переписывать код...
И заодно подучить Select .. SQL



Исправлено 1 раз(а). Последнее : Вячеслав Клепинин, 22.03.07 14:42
Ratings: 0 negative/0 positive
Re: Можно ли в этой задачке обойтись только реляционными командами?
leonid

Сообщений: 3202
Откуда: Рига
Дата регистрации: 03.02.2006
Вячеслав Клепинин
Ещё раз спасибо!
Не за что.
Цитата:
full join. Я его практически по жизни использовал пару раз, не больше...
Я его тоже очень редко использовал, но именно в задачах, где сравниваются два периода.
Ratings: 0 negative/0 positive
Re: Можно ли в этой задачке обойтись только реляционными командами?
Вячеслав Клепинин

Сообщений: 1597
Откуда: Санкт-Петербург
Дата регистрации: 26.03.2004
Для небольших объёмов данных это вполне подходит, меньше кода получается.
Но для больших... Так как в результате FULL JOIN мы получаем декартово произведение, то время выполнения будет пропорционально произведению записей в обеих курсорах. У нас мониторятся 40 газет, поэтому промежуточная выборка содержит всего 1600 записей, и это обрабатывается практически мгновенно.
Ratings: 0 negative/0 positive
Re: Можно ли в этой задачке обойтись только реляционными командами?
leonid

Сообщений: 3202
Откуда: Рига
Дата регистрации: 03.02.2006
Да нет, в таком варианте нет никакого декартова произведения
full outer join tmp2 t2 on t1.id_smi=t2.id_smi
Просто берется inner join и к нему добляются хвосты от обеих таблиц, не имеющих соответствия. Я сейчас запустил приведенный пример на 100000, сработало очень быстро, с декартовым произведением застряло бы.
Ratings: 0 negative/0 positive
Re: Можно ли в этой задачке обойтись только реляционными командами?
Igor Korolyov
Автор

Сообщений: 34580
Дата регистрации: 28.05.2002
Hi Вячеслав!

Декартово произведение появится если совсем убрать условие связи - т.е. ON (чего синтаксис с JOIN не позволяет - тока если по старинке через запятую источники перечислять) или если условие связыает поля, которые в обеих таблицах во ВСЕХ записях идентичны (что встречается конечно очень редко). Во всех прочих случаях не получится декартова произведения - т.е. объём выборки не будет составлять N*M записей (где N и M - объёмы "объединяемых" таблиц).


------------------
WBR, Igor
Ratings: 0 negative/0 positive


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

On-line: 1 (Гостей: 1)

© 2000-2024 Fox Club 
Яндекс.Метрика