![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Решил я по совету использовать курсоры, чтобы вернуть результат нескольких запросов в одном резалтсете. Ну то есть решить проблему 1+N запросов.
Сделал такой примерчик
ссылко1
ссылко2, скрипт
По идее, на каждую строку результсета должен вернутся открытый курсор, то бишь, мы фетчим внешний резалтсет, а внутри цикла фетча пытаемся фетчить полученный курсор.
На данный момент пока хрен что у меня получается, т.к. все компоненты доступа(и в дельфи, и в дотнете) возвращают первое поле запроса результат запроса "select * from myfunc() as test(a refcursor,b varchar(40))" видят тупо как строку и ни с какого бока к этому курсору не подступится.
Синтаксис работы с курсорами и возвращения множеств из функций postgresql тоже в некотором роде печалит, но это следствие видимо того, что я привык в этому плане к аккуратному синтаксису Firebird.
PS: Кстати, что забавно: в примерах везде приведены только самые простые случаи типа "возвращаем один курсор, возвращаем два заведомо известных курсора", а вот комбинацию "возвращаем множество туплов из курсора и атомарного типа" пришлось придумывать самому, с извращениями в виде create type.
PPS: Гамон. Победил эту хрень. исправленный скрипт (отличия - именование курсора и убрано его закрытие)
1)курсоры нужно именовать уникально, типа
cur='returnedcursor' || cast(parentid as varchar);
2)курсоры не нужно закрывать, т.к. второй запрос выполняется только после того как целиком выполнится первый, а не внутри него, как хотелось бы.
3)возвращенное в первом запросе имя курсора нужно использовать, чтобы обратится к его результатам:
Delphi: 'fetch all from '+q.Fields[0].AsString;
.NET: cmd2.CommandText = "FETCH ALL FROM "+reader1.GetString(0);
4)в дотнете это работает только с PreloadReader=true, иначе ругается что "уже открыт DataReader", я про это уже писал, что только Firebird умеет открывать более одного ридера.
В общем, те же яйца, вид в профиль.
Не знаю, как насчет парсинга запроса и кэширования результата парсинга, запросто может быть, что оно каждый раз во внутреннем цикле это делает повторно, то бишь опять та же проблема 1+N, только стоя и в гамаке.
Кроме того, сразу видно, что PL/pgSQL это ад, т.к. присваивая переменной курсора имя, мы делаем это имя до закрытия курсора доступным в FETCH ALL FROM, то есть, явное смешение данных и метаданных. Это можно было бы считать метапрограммированием, но это больше похоже на динамическую типизацию(анафема!!).
Сделал такой примерчик
ссылко1
ссылко2, скрипт
По идее, на каждую строку результсета должен вернутся открытый курсор, то бишь, мы фетчим внешний резалтсет, а внутри цикла фетча пытаемся фетчить полученный курсор.
На данный момент пока хрен что у меня получается, т.к. все компоненты доступа(и в дельфи, и в дотнете) возвращают первое поле запроса результат запроса "select * from myfunc() as test(a refcursor,b varchar(40))" видят тупо как строку и ни с какого бока к этому курсору не подступится.
Синтаксис работы с курсорами и возвращения множеств из функций postgresql тоже в некотором роде печалит, но это следствие видимо того, что я привык в этому плане к аккуратному синтаксису Firebird.
PS: Кстати, что забавно: в примерах везде приведены только самые простые случаи типа "возвращаем один курсор, возвращаем два заведомо известных курсора", а вот комбинацию "возвращаем множество туплов из курсора и атомарного типа" пришлось придумывать самому, с извращениями в виде create type.
PPS: Гамон. Победил эту хрень. исправленный скрипт (отличия - именование курсора и убрано его закрытие)
1)курсоры нужно именовать уникально, типа
cur='returnedcursor' || cast(parentid as varchar);
2)курсоры не нужно закрывать, т.к. второй запрос выполняется только после того как целиком выполнится первый, а не внутри него, как хотелось бы.
3)возвращенное в первом запросе имя курсора нужно использовать, чтобы обратится к его результатам:
Delphi: 'fetch all from '+q.Fields[0].AsString;
.NET: cmd2.CommandText = "FETCH ALL FROM "+reader1.GetString(0);
4)в дотнете это работает только с PreloadReader=true, иначе ругается что "уже открыт DataReader", я про это уже писал, что только Firebird умеет открывать более одного ридера.
В общем, те же яйца, вид в профиль.
Не знаю, как насчет парсинга запроса и кэширования результата парсинга, запросто может быть, что оно каждый раз во внутреннем цикле это делает повторно, то бишь опять та же проблема 1+N, только стоя и в гамаке.
Кроме того, сразу видно, что PL/pgSQL это ад, т.к. присваивая переменной курсора имя, мы делаем это имя до закрытия курсора доступным в FETCH ALL FROM, то есть, явное смешение данных и метаданных. Это можно было бы считать метапрограммированием, но это больше похоже на динамическую типизацию(анафема!!).
no subject
Date: 2010-10-03 08:13 am (UTC)no subject
Date: 2010-10-03 08:21 am (UTC)no subject
Date: 2010-10-03 08:47 am (UTC)no subject
Date: 2010-10-03 08:51 am (UTC)no subject
Date: 2010-10-03 09:20 am (UTC)no subject
Date: 2010-10-03 09:44 am (UTC)Простейшая операция, но почему-то везде, кроме дельфей тянущая за собой какое-то невменяемое вуду.
Т.е. препарим два запроса, выполняем первый, фетчим его, в процессе фетча подставляем значение поля из первого запроса в качестве параметра для второго, выполняем и во внутреннем цикле фетчим второй запрос.
Очевидно, желательно чтобы запроы препарились-парсились один раз - в начале всей операции, и чтобы потребление памяти сервером и клиентов было O(1).
В Firebird в таком случае сервер создает два запроса, на клиенте держатся их хендлы, которые можно использовать для установки параметров, выполнения и фетча.
В Postgresql параметры в запрос подставляет почему-то клиентская либа, на каждое внутреннее выполнение посылая новый текст запроса. Умеет он ли при этом заменить литерал на параметр и использовать ранее скэшированный результат препаре - вопрос сложный.
В MSSQL и дотнете такое вообще без дополнительного параметра Multiple Active Result Sets = True не работает, и этот параметр тянет за собой какие-то другие проблемы.
no subject
Date: 2010-10-03 01:59 pm (UTC)Ну о чем и речь. В постгресе аж два варианта:
1.
2.
В оракле один, с одной стороны чуть поудобнее, с другой - чуть понеудобнее, оракловые курсоры в резалтсете специфичней:
Разумеется, и в том и в другом случае в результирующих курсорах могут быть другие курсоры и т.д.
Я активно использую и постгресовый, и оракловый вариант и очень доволен.
no subject
Date: 2010-10-03 02:35 pm (UTC)no subject
Date: 2010-10-03 02:47 pm (UTC)Это где там такое написано?
no subject
Date: 2010-10-03 03:12 pm (UTC)"Currently, functions returning sets can also be called in the select list of a query. For each row that the query generates by itself, the function returning set is invoked, and an output row is generated for each element of the function's result set. Note, however, that this capability is deprecated and might be removed in future releases."