Вопрос по SQL

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

Вопрос по SQL

Сообщение v-t-l » 04.10.2007 17:54:08

Понимаю что вопрос скорее на sql.ru, но может здесь кто знает?
Вполне жизненная ситуация - имеется таблица:
Код: Выделить всё
Дата    |Цена
=============
01.08.07|1000
14.09.07|1234
22.10.07|1500

Как должен выглядеть запрос, чтобы получить
Код: Выделить всё
Цена|ДатаС   |ДатаПо
======================
1000|01.08.07|14.09.07
1234|14.09.07|22.10.07
1500|22.10.07|

Если важно, то SQL - Firebird 2.0

Заранее спасибо.
v-t-l
энтузиаст
 
Сообщения: 706
Зарегистрирован: 13.05.2007 16:27:22
Откуда: Belarus

Сообщение Attid » 04.10.2007 18:18:31

вопрос скорее на sql.ru,

угу

Если важно, то SQL - Firebird 2.0

угу, на разных серверах по разному будет.

проще все сделать процедуру, но можно и джойн самому к себе.
Аватара пользователя
Attid
долгожитель
 
Сообщения: 2583
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E

Сообщение v-t-l » 04.10.2007 18:27:03

JOIN - я как раз и думал об этом, но никак не придумаю условие связи?
v-t-l
энтузиаст
 
Сообщения: 706
Зарегистрирован: 13.05.2007 16:27:22
Откуда: Belarus

Сообщение shade » 04.10.2007 19:16:20

Можно попробовать что-то типа этого
Код: Выделить всё
SELECT t1.*, min(t2.Дата)
FROM t as t1, t as t2
WHERE  t1.Дата < t2.Дата
GROUP BY t1.Дата

Правда потеряется последняя строчка - там уж сами подумайте как замутить join
Аватара пользователя
shade
энтузиаст
 
Сообщения: 879
Зарегистрирован: 21.02.2006 20:15:48
Откуда: http://shamangrad.net/

Сообщение v-t-l » 04.10.2007 22:29:37

Нашел вариант:
Код: Выделить всё
SELECT
  t1.FPrice,
  t1.FDate,
(SELECT MIN(FDate) FROM TBL_PRICE AS t2 WHERE  t1.FDate < t2.FDate)
FROM TBL_PRICE as t1


Не проверял, правда, на больших объемах. Есть подозрение, что будет тормозить. Если у кого-нибудь есть еще идеи - welcome :)
v-t-l
энтузиаст
 
Сообщения: 706
Зарегистрирован: 13.05.2007 16:27:22
Откуда: Belarus

Сообщение alexs » 04.10.2007 22:43:49

v-t-l писал(а):Нашел вариант:

вот этот вариант наиболее хорош
чтобы не тормозил - необходим индекс
MIN кажется умеет использовать в птице индекс - надо просто посмотреть в документации и что выдаст на это IBExpert в статистике запросов
Аватара пользователя
alexs
долгожитель
 
Сообщения: 3912
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

Сообщение v-t-l » 05.10.2007 18:28:14

Код: Выделить всё
SELECT
  t1.FPrice,
  t1.FDate,
(SELECT MIN(FDate) FROM TBL_PRICE AS t2 WHERE  t1.FDate < t2.FDate)
FROM TBL_PRICE as t1


Проверил на больших объемах. Сгенерировал миллион записей случайных данных, создал индексы по обоим полям. Тормозит - минимум 10 минут на выборку. Пробовал по интервалу
Код: Выделить всё
SELECT
  t1.FPrice,
  t1.FDate,
(SELECT MIN(FDate) FROM TBL_PRICE AS t2 WHERE  t1.FDate < t2.FDate)
FROM TBL_PRICE as t1
WHERE t1.FDate BETWEEN '01.01.2007' AND '01.09.2007'

Выборка возвращает около 30000 записей, но выполняется еще дольше на пару минут.
Я так думаю, у огнептицы "план" неправильный (PLAN)
:lol:
Где взять лучший, в смысле как правильно указать ему последовательность операций?
v-t-l
энтузиаст
 
Сообщения: 706
Зарегистрирован: 13.05.2007 16:27:22
Откуда: Belarus

Сообщение Brainenjii » 05.10.2007 19:25:51

может я не прав, но можно ввести суррогатный ключ ID, и генератором его заполнять, и тогда выборка будет примерно такая
Код: Выделить всё
SELECT FDATE, FPRICE, (SELECT FDATE FROM TEST AS T1 WHERE T1.ID = T2.ID + 1) FROM TEST AS T2
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1352
Зарегистрирован: 10.05.2007 00:04:46

Сообщение Сергей Смирнов » 05.10.2007 21:21:40

Вам тестирование по SQL надо пройти или чтобы работало нормально? Во втором случае изготовление нехитрой ХП даст гарантию построения выборки за один проход правильно отсортированной таблицы. Прирост скорости тут возможен на 1-3 порядка по сравнению с запросом в зависимости от степени его кривизны.

Кроме того, даты начала и конца периода в соседних строках у Вас совпадают, что не есть гуд, если подразумевается какая-то практическая польза от результата. Это тоже неплохо бы учесть.
Аватара пользователя
Сергей Смирнов
энтузиаст
 
Сообщения: 595
Зарегистрирован: 28.04.2005 13:23:25
Откуда: Москва

Сообщение v-t-l » 06.10.2007 14:50:17

Мне нужно, чтобы работало быстро с выборкой по периоду.
ХП не подходит, т.к. это будет использоваться в редактируемых представлениях (updatable views).
Практическая польза - получение длительности действия каждого значения (цены в данном случае) для дальнейших расчетов.
Что касается метода, предложенного Brainenjii, то не факт, что даты будут вставляться последовательно.
Код: Выделить всё
SELECT
  t1.FPrice,
  t1.FDate,
(SELECT MIN(FDate) FROM TBL_PRICE AS t2 WHERE  t1.FDate < t2.FDate)
FROM TBL_PRICE as t1
WHERE t1.FDate BETWEEN '01.01.2007' AND '01.09.2007'

Здесь наверняка все дело в порядке выполнения запроса - нужно заставить огнептицу сначала ограничить выборку по периоду (WHERE t1.FDate BETWEEN '01.01.2007' AND '01.09.2007'), а уж затем приступать к выборке результирующих полей. Для этого, как я понимаю, есть (по крайней мере в 2.0+) ключевое слово PLAN, вот только как им пользоваться - непонятно.

Вот какой план показывает IBExpert:
Код: Выделить всё
План
PLAN (T2 ORDER TBL_PRICE_IDX2 INDEX (TBL_PRICE_IDX2))
PLAN (T1 INDEX (TBL_PRICE_IDX2))

Адаптированный план
PLAN (T2 ORDER TBL_PRICE_IDX2 INDEX (TBL_PRICE_IDX2)) PLAN (T1 INDEX (TBL_PRICE_IDX2))
v-t-l
энтузиаст
 
Сообщения: 706
Зарегистрирован: 13.05.2007 16:27:22
Откуда: Belarus

Сообщение Attid » 06.10.2007 17:10:28

v-t-l
если нужно чтоб быстро работало добавь поле, дабавь тригер который будет его обновлять, пройдись один раз update и будет тебе счастье, зачем городить огород ?
Аватара пользователя
Attid
долгожитель
 
Сообщения: 2583
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E

Сообщение debi12345 » 07.10.2007 02:20:38

Можно попробовать нечто типа :

select
t1.fprice,
t1.fdate as fdatebegin,
min(t2.fdate) as fdateend
from
t as t1,
t as t2
where
t2.fdate > t1.fdate
group by
t1.fprice,
t1.fdate;


Если даты в таблице все время возрастают, а не повторяются - проиндексировать. Если не повторяются только в пределах цены - не индексировать, или проиндексировать составным индексом "цена+дата".
Аватара пользователя
debi12345
долгожитель
 
Сообщения: 5615
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Сообщение alexs » 08.10.2007 16:55:08

Вот смотри пример:
Код: Выделить всё
select
  tb_price1.tb_price_id,
  tb_price1.spr_3_id,
  tb_price1.tb_price_date,
  tb_price1.tb_price_price1,
  (select
     max(tb_price2.tb_price_date)
   from
     tb_price tb_price2
   where
       tb_price2.tb_price_date < tb_price1.tb_price_date
     and
       tb_price2.spr_3_id = tb_price1.spr_3_id
  )
from
  tb_price tb_price1

где
tb_price - таблица с ценами (порядка милиона записей)
tb_price.spr_3_id - код товарной карточки

на таблице tb_price есть индекс по полям SPR_3_ID,TB_PRICE_DATE
тормозов не наблюдаю.
тем более в таком виде (без ограничения по товару) в живую запрос никто не делает - обычно дополнительно основной запрос ограничивается по коду товара, т.е.:
Код: Выделить всё
select
  tb_price1.tb_price_id,
  tb_price1.spr_3_id,
  tb_price1.tb_price_date,
  tb_price1.tb_price_price1,
  (select
     max(tb_price2.tb_price_date)
   from
     tb_price tb_price2
   where
       tb_price2.tb_price_date < tb_price1.tb_price_date
     and
       tb_price2.spr_3_id = tb_price1.spr_3_id
  )
from
  tb_price tb_price1
where
  tb_price1.spr_3_id = :spr_3_id
Аватара пользователя
alexs
долгожитель
 
Сообщения: 3912
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь


Вернуться в Общее

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 13

Рейтинг@Mail.ru