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

Cache': Как развернуть значение параметра в несколько строк

В некоторых случаях при использовании хранимых процедур ну очень хочется иметь механизм получения нескольких строк в select где значения строк определяются содержанием параметра запроса. Как это сделать в Cache?
Наша задача - принять перечень значений в виде одной строки - параметра запроса, которые разделены разделителем или как-то еще, например с разделителем - запятой. При выполнении запроса мы должны получить столько строк сколько этих значений передано в строке. Для развертывания строки - параметра применим идеи статей Cache': Как сделать select from dual и Cache': Где наши данные?.

Вынудим движок Cache применить select к определенному нами способу хранения так, чтобы перед обращением к нему мы могли принять параметр и сконструировать в локальной переменной такую конструкцию, из которой Cache взяла бы наши строки как строки sql таблицы. Назовем группу имен для этого трюка Expand. Экспериментировать будем с версией 5.0.

Создадим класс persistent с именем User.Expand, в котором и определим необходимые нам сущности:
Class User.Expand Extends %Persistent [ ClassType = persistent,
Not ProcedureBlock, SqlTableName = EXPAND ]
{

}
Чтобы принять значения параметров из строки, мы должны соблюдать соглашения SQL о передаче параметров и принять значение до того, как sql движок обратится к нашей условной таблице. Это можем сделать в написанной нами хранимой процедуре, которая примет значение параметра и по нему сконструирует с локальной переменной таблицу.
Class User.Expand Extends %Persistent [ ClassType = persistent,
Not ProcedureBlock, SqlTableName = EXPAND ]
{

ClassMethod Expand(Arg1 As %String) As %String [ SqlProc ]
{
 k zzzzexpand
 n i
 f i=1:1:$l(Arg1,",") s zzzzexpand($p(Arg1,",",i))=""
 q ""
}

}
При этом нам надо определить хранение данных так, чтобы sql движок достал наши данные как данные таблицы и стал применять к ним операции sql. Модифицируем способ хранения таблицы соответствующим способом:
Class User.Expand Extends %Persistent [ ClassType = persistent,
Not ProcedureBlock, SqlTableName = EXPAND ]
{

ClassMethod Expand(Arg1 As %String) As %String [ SqlProc ]
{
 k zzzzexpand
 n i
 f i=1:1:$l(Arg1,",") s zzzzexpand($p(Arg1,",",i))=""
 q ""
}

<Storage name="Default">
    <Data name="ExpandDefaultData">
        <Value name="1">
            <Value>%%CLASSNAME</Value>
        </Value>
    </Data>
    <DataLocation>zzzzexpand</DataLocation>
    <DefaultData>ExpandDefaultData</DefaultData>
    <IdLocation>zzzzexpand</IdLocation>
    <IndexLocation>zzzzexpand</IndexLocation>
    <StreamLocation>zzzzexpand</StreamLocation>
    <Type>%Library.CacheStorage</Type>
</Storage>

}
В результате получили возможность передать извне через хранимую процедуру значения в нашу условную таблицу. Например:
USER>d $System.SQL.Shell()
 
>>select ID, Expand_Expand('a,b,c,d,e,f') from Expand
(1)>>go
a
b
c
d
e
f
>>
В отличие от результатов экспериментов с условной таблицей dual в "Cache': Как сделать select from dual" мы явно и извне, с использованием параметра, задаем сколько строк нужно получить в select и какие у них должны быть значения.

Можем сделать view, которые будут возвращать заранее заданные наборы строк с заданными значениями, например:
create view abcdef1 as select ID, 
Expand_Expand('a,b,c,d,e,f') from Expand

create view abcdef as select ID from abcdef1

>>select * from abcdef
(1)>>go
a
b
c
d
e
f
>>
В отличие от гарантированности результата select из псевдотаблицы Dual в случае псевдотаблицы Expand я пока не могу дать гарантированного решения с несколькими такими таблицами в одном запросе, поскольку пока они используют одну и ту же локальную переменную.

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

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