Найти - Пользователи
Полная версия: SQLAlchemy как запросить хранимую процедуру с параметром?
Начало » Базы данных » SQLAlchemy как запросить хранимую процедуру с параметром?
1 2
baloo
Здравствуйте. Не смог найти ни капли материала. Есть stored procedure в FireBird'е - входящий параметр IN_NCONT, на выходе - OUT_NUNITCODE.
Сам запрос (без алхимии, обычный SQL) выглядит просто: SELECT OUT_NUNITCODE FROM SP_GET_NEW_NUNITCODE (:IN_NCONT)
И в Delphi все решается просто. А тут никак не придумаю.
baloo
Как начал, так и кончил. Последняя ссылка - вообще моя :(
Пробуем
res = Session.execute("SELECT OUT_NUNITCODE FROM PR_ASSIGN_NUNITCODE(:IN_NCONT)", ('1995'))
И получаем
⇝ AttributeError: ‘list’ object has no attribute ‘keys’
Пробуем
Session.execute("SELECT OUT_NUNITCODE FROM PR_ASSIGN_NUNITCODE(:IN_NCONT)").params(IN_NCONT = '1995').first()
Получаем ⇝ AttributeError: ‘ResultProxy’ object has no attribute ‘params’
Похоже, что не так-то просто задействовать все, что выходит за пределы обычных таблиц и запросов…
Lexander
Уточни, OUT_NUNITCODE - это именно выходной параметр процедуры (return или как там в FB) или столбец данных (хранимка возвращает набор данных)?
baloo
Выходной. Это не селективная процедура. Она запрашивет максимальный номер филиала, добавляет единицу и отдает новый номер.
Вот скрипт ХП:
CREATE OR ALTER PROCEDURE PR_ASSIGN_NUNITCODE (
in_ncont VARCHAR(4)) ##Входящая переменная (цифры, хоть и varchar - это специально)
RETURNS (
out_nunitcode VARCHAR(2)) ##Выходящая
AS
DECLARE VARIABLE v_i_nunitcode INTEGER; ##
begin
/* Procedure Text */
for select max(cast(contracts.nunitcode as integer))
from contracts
where contracts.ncont = :in_ncont
into :v_i_nunitcode ## Рабочая - обязательно надо куда-нить делать into
do
begin
out_nunitcode = cast((v_i_nunitcode+1) as varchar(2));
suspend; ## т.е. Return как бы...
end
end^

SET TERM ; ^

COMMENT ON PROCEDURE PR_ASSIGN_NUNITCODE IS
'Íàçíà÷àåò ìàêñèìàëüíûé íîìåð +1 ôèëèàëà';
baloo
Вот ночью пробовал:
    def qry(self, id=None):
res = Session.execute("SELECT OUT_NUNITCODE FROM PR_ASSIGN_NUNITCODE(?)", (id))

for row in res:
print id
print row.out_nunitcode
return u'сработало'
Если в id передать 1995, то процедура должна вернуть 9 (там уже 8 филиалов есть на договоре 1995)
Только вся эта конструкция выдает
 ⇝  AttributeError: 'list' object has no attribute 'keys'
View as: Interactive (full) | Text (full) | XML (full)
clear this
clear this
Module pyfield.controllers.contracts:201 in qry view
<< #----------------------------------------------------------------------
def qry(self, id=None):
res = Session.execute("SELECT OUT_NUNITCODE FROM PR_ASSIGN_NUNITCODE(?)", (id))
print id
#for row in res:
>> res = Session.execute("SELECT OUT_NUNITCODE FROM PR_ASSIGN_NUNITCODE(?)", (id))
Module sqlalchemy.orm.scoping:121 in do view
<< def instrument(name):
def do(self, *args, **kwargs):
return getattr(self.registry(), name)(*args, **kwargs)
return do
for meth in Session.public_methods:
>> return getattr(self.registry(), name)(*args, **kwargs)
Module sqlalchemy.orm.session:755 in execute view
<< return self.__connection(engine, close_with_result=True).execute(
clause, params or {})

def scalar(self, clause, params=None, mapper=None):
>> clause, params or {})
Module sqlalchemy.engine.base:824 in execute view
<< for c in type(object).__mro__:
if c in Connection.executors:
return Connection.executors[c](self, object, multiparams, params)
else:
raise exc.InvalidRequestError("Unexecutable object type: " + str(type(object)))
>> return Connection.executors[c](self, object, multiparams, params)
Module sqlalchemy.engine.base:866 in _execute_clauseelement view
<< params = self.__distill_params(multiparams, params)
if params:
keys = params[0].keys()
else:
keys = []
>> keys = params[0].keys()
AttributeError: 'list' object has no attribute 'keys'
По идее, там в доке по SA 5 есть пара слов про outparam - типа используется в stored procedure
И на этом все заканчивается. Надо ли отражать ее в модели, не надо ли… Как ее указывать? Как таблицу или для процедур свои примочки? Или можно употребить только при помощи литерального SQL…
Собсно, FireBird стыкуется с SA через kinterbasdb - прослойка, драйвер.
В Кинтербазе сказано, что использовать ХП надо так:

##To retrieve a result set from a stored procedure with KInterbasDB, use code such as this:

cur.execute("select output1, output2 from the_proc(?, ?)", (input1, input2))

# Ordinary fetch code here, such as:
for row in cur:
... # process row

con.commit() # If the procedure had any side effects, commit them.
Cur - курсор. Очевидно, это и есть Session. Между прочим, в доке к SA session с маленькой буквы. А, как я понял - session это вовсе не то же, что и Session
j2a
1. Session – это глобальный класс сессий, session – локальная сессия, session = Session()
2. SQLAlchemy session != DB API cursor (с чего, вдруг, “это очевидно, что cur и есть Session”)
3. Читай докстринги и ошибки внимательней.
AttributeError: ‘list’ object has no attribute ‘keys’
Он же ясно говорит – у списка нет атрибута “keys”. Ты в execute передаешь список, в help(session.execute) явно сказано:
execute(self, clause, params=None, mapper=None, instance=None)
Execute the given clause, using the current transaction (if any).

Returns a ``ResultProxy`` corresponding to the execution's results.

params
a dictionary of bind parameters.
Lexander
sqlalchemy.sql.expression.outparam(key, type_=None)

Create an ‘OUT’ parameter for usage in functions (stored procedures), for databases which support them.

The outparam can be used like a regular function parameter. The “output” value will be available from the ResultProxy object via its out_parameters attribute, which returns a dictionary containing the values.
baloo
tnx to Lexander, I've been written it too. That's non-usefull, потому что непонятно, где там этот аутпараметр вставлять.
Короче, после долгих мучений и уже принятого решения закольцевать это поле в самом firebirde при помощи триггера и просто переделать клиента на Delphi, чтобы он его не просил, нашлось мало-мальское решение:
Вот эта конструкция вроде работает:
return Session.execute("SELECT OUT_NUNITCODE FROM PR_ASSIGN_NUNITCODE(:in_ncont)", {'in_ncont' : id}).fetchone()
Возвращает то, что надо. И где тут outparam? Вообще в доках в основном только для баз-хранилищ вроде MySQL информация. А для SQL-серверов, имеющих встроенную динамику - шиш да кумыш.
А без SQL-запроса? Именно объектами SQLAlchemy никак неьлзя было решить?
j2a
Я использую PostgreSQL, там синтаксис хранимых функций – ‘SELECT func(arg1, arg2)’, средствами SQLAlchemy (sqlalchemy.select, sqlalchemy.func) обхожусь.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB