Как сделать запрос

Запросы, планы, оптимизация запросов, ...

Модераторы: kdv, CyberMax

Ответить
RhinoFC
Сообщения: 11
Зарегистрирован: 17 ноя 2004, 09:36

Как сделать запрос

Сообщение RhinoFC » 17 ноя 2004, 09:43

Есть запрос вида:

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

select fld1, fld2 from table1
where [некое условие]
order by fld2 desc
rows 1
Запрос вернет одну запись, где fld2 - максимальное (из диапазона записей, удовлетворяющих условию выборки).

Мне нужно сделать тоже самое, но не используя rows.
Все это дело будет использовано внутри ХП, и первое, что приходит на ум, это найти сначала, максимальное значение fld2 из записей, удовлетворяющих условию выборки. Но это тяжко. Процедура будет работать очень медленно. Как вообще решались такие проблемы до появления Rows?

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 17 ноя 2004, 10:40

в процедурах - никак. на клиенте - выбиралась первая запись и потом запрос закрывался, т.е. выборка всех остальных записей не делалась. rows/first делает именно это, в т.ч. в процедурах.

sag
Сообщения: 116
Зарегистрирован: 02 ноя 2004, 11:42

Сообщение sag » 17 ноя 2004, 10:50

> Мне нужно сделать тоже самое, но не
> используя rows. Все это дело будет
> использовано внутри ХП

в хп делай цикл FOR SELECT по этому запросу, а после
получения первой записи выходи из цикла

Гость

Сообщение Гость » 17 ноя 2004, 11:07

sag писал(а):в хп делай цикл FOR SELECT по этому запросу, а после
получения первой записи выходи из цикла
Интересно. И как же в хп выйти из цикла? Я понимаю, конечно, что можно в цикле просмотреть одну запись а остальные проигнорировать. Но цикл-то все равно прокрутит все записи. Может быть и черт с ним, если это не займет много времени. Как думаете?

RhinoFC
Сообщения: 11
Зарегистрирован: 17 ноя 2004, 09:36

Сообщение RhinoFC » 17 ноя 2004, 11:32

Может быть в этом случае вообще сделать вот так?:

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

for select fld1, fld2 from table1
where [некое условие]
order by fld2 /* ASC */
into :f1, :f2
do
begin
  f1 = f1;
end
Тогда ведь в f1 и f2 окажутся как раз значения из нужной записи. Но, во-первых, цикл все-равно пройдет по всем записям, а во-вторых необходим какой-нибудь "пустой" оператор, который ничего не делает (я выбрал f1=f2), кроме того, что тратит процессорное время.

sag
Сообщения: 116
Зарегистрирован: 02 ноя 2004, 11:42

Сообщение sag » 17 ноя 2004, 11:35

> И как же в хп выйти из цикла? Я понимаю, конечно,
> что можно в цикле просмотреть одну запись а
> остальные проигнорировать.

Не, это не наши методы.
На «старых» иб-подобных для этих целей можно применить,
например, механизм пользовательских исключений:

...
/*получаем первую запись запроса*/
begin
for select ...
do
begin
...
exception my_exception; /*"возбуждаем" исключение*/
end
when exception my_exception do ...; /*ловим исключение
после первой итерации цикла*/
end
.... /*продолжаем выполнение хп*/

dimitr
Разработчик Firebird
Сообщения: 888
Зарегистрирован: 26 окт 2004, 16:20

Сообщение dimitr » 17 ноя 2004, 11:36

Из FOR SELECT цикла можно выйти, выбросив исключение и перехватив его потом на уровень выше в пустом WHEN-обработчике. Я так понимаю, что сервер - IB?

RhinoFC
Сообщения: 11
Зарегистрирован: 17 ноя 2004, 09:36

Сообщение RhinoFC » 17 ноя 2004, 12:14

sag, спасибо. Помогло :)

Гость

Сообщение Гость » 17 ноя 2004, 13:34

А так не проще (для 1 строки):

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

Select fld1, fld2 from table1 
where [некое условие] 
order by fld2 /* ASC */ 
into :f1, :f2 ;
suspend;
Для X строк - While и переменная-счетчик.

sag
Сообщения: 116
Зарегистрирован: 02 ноя 2004, 11:42

Сообщение sag » 17 ноя 2004, 15:03

> А так не проще (для 1 строки):
> Select fld1, fld2 from table1
> where [некое условие]

Что есть "некое условие"? Каждому пользователю системы раздать по генератору? Если ты имеешь в виду что-то другое, то научи, пжалста.

Vemer
Сообщения: 8
Зарегистрирован: 09 ноя 2004, 15:01

Сообщение Vemer » 18 ноя 2004, 16:24

Имелось ввиду что просто
Select ... Into ..; Suspend;(без For)
Вернет первую строку в выходные параметры независимо от условий.
А кол-во нужных строк можно задавать с помощью входного параметра. И при чем тут генераторы?

sag
Сообщения: 116
Зарегистрирован: 02 ноя 2004, 11:42

Сообщение sag » 19 ноя 2004, 08:23

> Имелось ввиду что просто
> Select ... Into ..; Suspend;(без For)
> Вернет первую строку в выходные параметры
> независимо от условий. А кол-во нужных строк
> можно задавать с помощью входного параметра.

?
В случае если этот запрос возвращает только одну строку, то он ее единственную и, в этом случае, первую (последнюю) же и вернет. Если же запрос возвращает несколько строк, то получите пожалуйста: "multiple rows in singleton select". Это требовалось? И как здесь можно задействовать входной параметр?

>И при чем тут генераторы?

Если не брать вариант с перебором всех строк выборки (посредством for select-а), есть еще извратный вариант пригодный для однопользовательских систем или для очень-очень редких операций. Я имею в виду использование проверки значения генератора в секции where запроса.
...
i=gen_id(my_generator, ...); /*устанавливаем генератор в единицу, например*/
for
select ...
from ...
where gen_id(my_generator,0)>0 /*проверяем значение генератора, это и есть некое условие*/
order by ...
into :...
do
begin
suspend;
i=gen_id(my_generator, ...); /*устанавливаем генератор в ноль*/
end
/*получили первую запись и продолжаем выполнение хп*/

Ответить