Вопрос по SQL

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

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

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

Вопрос по SQL

Сообщение v-t-l »

Понимаю что вопрос скорее на 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

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

Сообщение Attid »

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

угу

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

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

проще все сделать процедуру, но можно и джойн самому к себе.
v-t-l
энтузиаст
Сообщения: 744
Зарегистрирован: 13.05.2007 16:27:22
Откуда: Belarus

Сообщение v-t-l »

JOIN - я как раз и думал об этом, но никак не придумаю условие связи?
Аватара пользователя
shade
энтузиаст
Сообщения: 879
Зарегистрирован: 21.02.2006 19:15:48
Откуда: http://shamangrad.net/
Контактная информация:

Сообщение shade »

Можно попробовать что-то типа этого

Код: Выделить всё

SELECT t1.*, min(t2.Дата)
FROM t as t1, t as t2
WHERE  t1.Дата < t2.Дата
GROUP BY t1.Дата

Правда потеряется последняя строчка - там уж сами подумайте как замутить join
v-t-l
энтузиаст
Сообщения: 744
Зарегистрирован: 13.05.2007 16:27:22
Откуда: Belarus

Сообщение v-t-l »

Нашел вариант:

Код: Выделить всё

SELECT
  t1.FPrice,
  t1.FDate,
 (SELECT MIN(FDate) FROM TBL_PRICE AS t2 WHERE  t1.FDate < t2.FDate)
FROM TBL_PRICE as t1


Не проверял, правда, на больших объемах. Есть подозрение, что будет тормозить. Если у кого-нибудь есть еще идеи - welcome :)
Аватара пользователя
alexs
долгожитель
Сообщения: 4069
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь
Контактная информация:

Сообщение alexs »

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

вот этот вариант наиболее хорош
чтобы не тормозил - необходим индекс
MIN кажется умеет использовать в птице индекс - надо просто посмотреть в документации и что выдаст на это IBExpert в статистике запросов
v-t-l
энтузиаст
Сообщения: 744
Зарегистрирован: 13.05.2007 16:27:22
Откуда: Belarus

Сообщение v-t-l »

Код: Выделить всё

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:
Где взять лучший, в смысле как правильно указать ему последовательность операций?
Аватара пользователя
Brainenjii
энтузиаст
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Сообщение Brainenjii »

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

Код: Выделить всё

SELECT FDATE, FPRICE, (SELECT FDATE FROM TEST AS T1 WHERE T1.ID = T2.ID + 1) FROM TEST AS T2
Аватара пользователя
Сергей Смирнов
энтузиаст
Сообщения: 595
Зарегистрирован: 28.04.2005 13:23:25
Откуда: Москва
Контактная информация:

Сообщение Сергей Смирнов »

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

Кроме того, даты начала и конца периода в соседних строках у Вас совпадают, что не есть гуд, если подразумевается какая-то практическая польза от результата. Это тоже неплохо бы учесть.
v-t-l
энтузиаст
Сообщения: 744
Зарегистрирован: 13.05.2007 16:27:22
Откуда: Belarus

Сообщение v-t-l »

Мне нужно, чтобы работало быстро с выборкой по периоду.
ХП не подходит, т.к. это будет использоваться в редактируемых представлениях (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))
Аватара пользователя
Attid
долгожитель
Сообщения: 2589
Зарегистрирован: 27.10.2006 17:29:15
Откуда: 44°32′23.63″N 41°2′25.2″E
Контактная информация:

Сообщение Attid »

v-t-l
если нужно чтоб быстро работало добавь поле, дабавь тригер который будет его обновлять, пройдись один раз update и будет тебе счастье, зачем городить огород ?
Аватара пользователя
debi12345
долгожитель
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Сообщение debi12345 »

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

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;


Если даты в таблице все время возрастают, а не повторяются - проиндексировать. Если не повторяются только в пределах цены - не индексировать, или проиндексировать составным индексом "цена+дата".
Аватара пользователя
alexs
долгожитель
Сообщения: 4069
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь
Контактная информация:

Сообщение alexs »

Вот смотри пример:

Код: Выделить всё

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
Ответить