green_fr: (Default)
[personal profile] green_fr

У меня есть таблица с курсами ценных бумаг. Скажем, колонки POS_DARR, POS_COD и POS_COURS для даты, кода бумаги и курса.
В программе, заполняющей эту таблицу могут быть баги, когда курс застывает на некотором значении, и перестаёт обновляться, т.е. начиная со дня баги курс будет равен одному и тому же значению.
Мне нужно вывести все подозрительные линии, т.е. для некоторой даты вывести все коды, курсы которых не изменились по крайней мере со вчерашнего дня (халява), а затем дату, с которой этот курс оставался неизменным.

Я написал следующего монстра (POSITION - таблица курсов, код не в одной колонке POS_COD, а в двух POS_PTF_COD и POS_VAL_COD, INTEGRATION - список всех дат базы данных):

select pos_darr, min(int_darr), pos_ptf_cod, pos_val_cod, pos_cours
from (
select pos1.pos_darr, int_darr, pos1.pos_ptf_cod, pos1.pos_val_cod, pos1.pos_cours
from position pos1, position pos2, integration
where pos1.pos_darr = '20/07/2006'
and pos1.pos_val_cod = 'FR0000108664'
and pos1.pos_ptf_cod = '1000101'
and pos1.pos_ptf_cod = pos2.pos_ptf_cod
and pos1.pos_val_cod = pos2.pos_val_cod
and int_darr < pos1.pos_darr
and pos1.pos_darr > pos2.pos_darr
and int_darr <= pos2.pos_darr
group by pos1.pos_darr, pos1.pos_ptf_cod, pos1.pos_val_cod, pos1.pos_cours, int_darr
having min(pos2.pos_cours) = max(pos2.pos_cours)
)
group by pos_darr, pos_ptf_cod, pos_val_cod, pos_cours

Монстра работает, конечно, но только когда я запрашиваю один код (как это сдалено в примере). Когда прошу много - думает тормозит. Неудивительно, впрочем. Есть какие-то идеи, как вообще такие вещи пишутся?

Можно, конечно, писать не запрос, а цикл, который пробегает по курсору... Но хочется красиво как-то.

Date: 2006-08-09 08:07 am (UTC)
From: [identity profile] aguti.livejournal.com
not exists всегда тормозит, в оличие от exists - ведь ему надо перелопатить всю таблицу, прежде чем ответить на вопрос.
А какие индексы у тебя уже есть?

Date: 2006-08-09 08:27 am (UTC)
From: [identity profile] genem.livejournal.com
А если найти сперва все которые не поменялись со вчера, сложить их во временную таблицу - должно быть не так много же ж. Потом с ней джойнить и искать минимальную дату монстром?

Date: 2006-08-09 08:33 am (UTC)
From: [identity profile] aguti.livejournal.com
Даже еще проще: во время апдейта проверить, поменялось ли значение, и если да - обновить дату во вспомогательной таблице. Так в ней всегда самая старая дата для этого курса. Но, как сказал green_fr, мы не ищем легких путей :)

Date: 2006-08-09 08:34 am (UTC)
From: [identity profile] green-fr.livejournal.com
И это я тоже попробовал :-) Читабельность при этом возросла невломенно, в отличие от скорости.

Date: 2006-08-09 08:32 am (UTC)
From: [identity profile] green-fr.livejournal.com
DARR+PTF_COD
DARR+VAL_COD
PTF_COD+VAL_COD+DARR

Но мне же нужен только DARR, т.е. любой их первых двух прокатывает.
Я в итоге решил даже процедуру не писать, а сделать, как ты предложила - в момент смены курса просчитывать дату и писать её куда-нибудь уже готовенькую.

По поводу "микрософту" - это работали мы с [livejournal.com profile] genem в Москве, был там культовый запрос пользователей. Машина, типа, тормозит, просим добавить памяти и микрософту.

Date: 2006-08-09 10:06 am (UTC)
From: [identity profile] aguti.livejournal.com
Правильное решение. Но попробуй еще этот запрос, мне просто интересно:

select distinct pos_ptf_cod, pos_val_cod, first_value(pos_darr) over
(partition by pos_ptf_cod, pos_val_cod order by pos_darr) mindate
from position a
where pos_darr < '20/07/2006'
and not exists
(select 1
from position
where pos_ptf_cod = a.pos_ptf_cod
and pos_val_cod = a.pos_val_cod
and pos_darr >= a.pos_darr
and pos_darr <= '20/07/2006'
and pos_cours != a.pos_cours
)

Date: 2006-08-09 11:18 am (UTC)
From: [identity profile] green-fr.livejournal.com
Это же слово в слово то, что Женька парой комментов выше предложил. Красиво, читабельно, но тормозит тоже жутко.
Кстати, не знал, что можно в таком случае сделать alias одной instance таблицы position, а вторую оставить без alias. Век живи, век учись :-)

Date: 2006-08-09 11:34 am (UTC)
From: [identity profile] aguti.livejournal.com
Не слово в слово, а без group by :) Мне было интересно, будет ли first_value работать быстрее min (у меня нет под рукой достаточно большой базы, чтобы проверить).

Date: 2006-08-09 01:01 pm (UTC)
From: [identity profile] green-fr.livejournal.com
110 секунд на твой вариант, столько же на Женькин.
Для сравнения, мой показывал что-то в районе 500 :-)

Date: 2006-08-11 06:58 pm (UTC)
From: [identity profile] zadiraka.livejournal.com
Значит надо LEFT JOIN применять вместо not exists.

Date: 2006-08-12 12:23 pm (UTC)
From: [identity profile] green-fr.livejournal.com
А почему ты думаешь, что left join будет работать как-то по-другому?

Profile

green_fr: (Default)
green_fr

May 2025

S M T W T F S
    1 23
4 5 678910
11 12 1314 15 1617
18192021222324
25262728293031

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated May. 28th, 2025 01:42 am
Powered by Dreamwidth Studios