понедельник, 11 апреля 2016 г.

Cache': Как сделать select from limit

В некоторых случаях, при использовании sql, нужно ограничить выборку числа строк, указав с какой строки выдать и сколько строк выдать. Как сделать то же самое в Cache?
Чтобы ограничить выборку, нам нужно передать в запрос два значения, начиная с какой строки результата запроса выдавать и сколько записей выдать. Такая задача характерна для выдачи данных постранично - один запрос, но выдать надо различные его части.

Используем хранимые процедуры и поведенческую модель движка cache. Если запросить в колонке результат хранимой процедуры так, что в ее параметрах не используются данные из таблиц, то cache вызывает ее однократно перед выполнением запроса. В нее и передадим первое значение - с какой строки выдавать записи. Второй параметр - сколько строк выдать - передадим в хранимую процедуру, использованную в условии where, причем так, что в ее параметр передается какая-либо колонка из таблицы. Это вынудит движок cache применять фильтрацию по этому условию. Мы, в хранимой процедуре, сверим количество обращений к ней и примем решение - подходит эта строка под выдачу или нет.
Так выглядит общая схема запроса:
select ID, LimitFrom( from_number)
from table 
where LimitTo( table.ID, to_number)=1
Используем локальную переменную для взаимодействия двух хранимых процедур:
ClassMethod LimitFrom(Arg1 As %String) As %String [ SqlProc ]
{
 k zzzlimit
 ; счетчик обращений
 s zzzlimit=0
 ; начальное значение для пропуска
 s zzzlimit(1)=+$g(Arg1) 
 q ""
}

ClassMethod LimitTo(dummy, Arg1 As %String) As %Integer [ SqlProc ]
{
 ; увеличили счетчик заходов в фильтр LIMIT
 i $i(zzzlimit)    
 ; первые которые надо пропустить
 i zzzlimit<zzzlimit(1) q 0  
 ; концевые которые надо пропустить
 i zzzlimit>(Arg1+zzzlimit(1)-1) q 0  
 ; этот заход попадает в интервал
 q 1   
}
Эти две процедуры существуют сами по себе и не привязаны ни к какой таблице. Чтобы не плодить лишних таблиц, я вписал их в класс Expand из заметки Cache': Как развернуть значение параметра в несколько строк и использовал из нее же условные данные, задаваемые извне. Поэтому получил имена sql процедур, декорированные именем Expand:
>>select ID, Expand_Expand('g,h,j,k,f,e,d,c,b,a,1'),
Expand_LimitFrom(3) from 
>>Expand where Expand_LimitTo(id,4)=1 order by ID
(1)>>go
b
c
d
e
>>
Здесь, для проверки запрашивается "выдать с третьей строки select четыре строки". Очевидно, что если задать "выдать с первой строки", то получим функциональный аналог TOP 4.

К плюсам полученного решения я отнесу тот факт, что если в запросе стоит order by, то движок каше сначала применяет сортировку, и после нее фильтрацию, применив хранимую функцию. К минусам - то, что хранимые процедуры используют одну и ту же локальную переменную и нельзя использовать несколько ограничений в одном сложном запросе.

Комментариев нет:

Отправить комментарий