хранимые процедуры с sqlAlchemy - PullRequest
       22

хранимые процедуры с sqlAlchemy

31 голосов
/ 25 августа 2010

Как я могу вызвать хранимые процедуры сервера sql с sqlAlchemy?

Ответы [ 6 ]

15 голосов
/ 25 августа 2010

Движки и соединения имеют метод execute(), который вы можете использовать для произвольных операторов SQL, как и Sessions. Например:

results = sess.execute('myproc ?, ?', [param1, param2])

Вы можете использовать outparam() для создания выходных параметров, если вам нужно (или для параметров связывания используйте bindparam() с опцией isoutparam=True)

8 голосов
/ 25 августа 2010

Просто выполните процедуру, созданную с помощью func:

from sqlalchemy import create_engine, func
from sqlalchemy.orm import sessionmaker

engine = create_engine('sqlite://', echo=True)
print engine.execute(func.upper('abc')).scalar() # Using engine
session = sessionmaker(bind=engine)()
print session.execute(func.upper('abc')).scalar() # Using session
6 голосов
/ 15 октября 2012

Если у вас уже есть сеанс, созданный с помощью sessionmaker (), вы можете использовать следующую функцию:

def exec_procedure(session, proc_name, params):
    sql_params = ",".join(["@{0}={1}".format(name, value) for name, value in params.items()])
    sql_string = """
        DECLARE @return_value int;
        EXEC    @return_value = [dbo].[{proc_name}] {params};
        SELECT 'Return Value' = @return_value;
    """.format(proc_name=proc_name, params=sql_params)

    return session.execute(sql_string).fetchall()

Теперь вы можете выполнить вашу хранимую процедуру «MyProc» с такими параметрами:

params = {
    'Foo': foo_value,
    'Bar': bar_value
}
exec_procedure(session, 'MyProc', params)
5 голосов
/ 24 апреля 2018

context : я использую flask-sqlalchemy с MySQL и без ORM-отображения.Обычно я использую:

# in the init method
_db = SqlAlchemy(app)

#... somewhere in my code ...
_db.session.execute(query)

Вызов хранимых процедур не поддерживается "из коробки": callproc не является общим, но специфичным для коннектора mysql.

Для хранимых процедур без параметров можно выполнить запрос, подобный

_db.session.execute(sqlalchemy.text("CALL my_proc(:param)"), param='something')

, как обычно.Все становится более сложным, когда у вас есть out params ...


Один из способов использовать params - получить доступ к базовому соединителю через engine.raw_connection().Например:

conn = _db.engine.raw_connection()
# do the call. The actual parameter does not matter, could be ['lala'] as well
results = conn.cursor().callproc('my_proc_with_one_out_param', [0])
conn.close()   # commit
print(results) # will print (<out param result>)

Это хорошо, так как мы можем получить доступ к параметру out, НО это соединение не управляется сеансом фляги .Это означает, что оно не будет зафиксировано / прервано, как с другими управляемыми запросами ... (проблематично, только если ваша процедура имеет побочный эффект).

Наконец я закончил тем, что сделал:

# do the call and store the result in a local mysql variabl
# the name does not matter, as long as it is prefixed by @
_db.session.execute('CALL my_proc_with_one_out_param(@out)')
# do another query to get back the result
result = _db.session.execute('SELECT @out').fetchone()

result будет кортежем с одним значением: выходной параметр.Это не идеально, но наименее опасно: если во время сеанса произойдет сбой другого запроса, вызов процедуры также будет прерван (откат).

4 голосов
/ 11 декабря 2015

Самый простой способ вызвать хранимую процедуру в MySQL с помощью SQLAlchemy - это использовать callproc метод Engine.raw_connection().call_proc потребует имя процедуры и параметры, необходимые для вызова хранимой процедуры.

def call_procedure(function_name, params):
       connection = cloudsql.Engine.raw_connection()
       try:
           cursor = connection.cursor()
           cursor.callproc(function_name, params)
           results = list(cursor.fetchall())
           cursor.close()
           connection.commit()
           return results
       finally:
           connection.close()
1 голос
/ 23 октября 2013

Из-за острой необходимости в моем проекте я написал функцию, которая обрабатывает вызовы хранимых процедур.

Вот, пожалуйста,

import sqlalchemy as sql

def execute_db_store_procedure(database, types, sql_store_procedure, *sp_args):
    """ Execute the store procedure and return the response table.

    Attention: No injection checking!!!

    Does work with the CALL syntax as of yet (TODO: other databases).

    Attributes:
        database            -- the database
        types               -- tuple of strings of SQLAlchemy type names.
                               Each type describes the type of the argument
                               with the same number.
                               List: http://docs.sqlalchemy.org/en/rel_0_7/core/types.html
        sql_store_procudure -- string of the stored procedure to be executed
        sp_args             -- arguments passed to the stored procedure
    """
    if not len(types) == len(sp_args):
        raise ValueError("types tuple must be the length of the sp args.")

    # Construch the type list for the given types
    # See
    # http://docs.sqlalchemy.org/en/latest/core/sqlelement.html?highlight=expression.text#sqlalchemy.sql.expression.text
    # sp_args (and their types) are numbered from 0 to len(sp_args)-1
    type_list = [sql.sql.expression.bindparam(
                    str(no), type_=getattr(sql.types, typ)())
                        for no, typ in zip(range(len(types)), types)]

    try:
        # Adapts to the number of arguments given to the function
        sp_call = sql.text("CALL `%s`(%s)" % (
                sql_store_procedure,
                ", ".join([":%s" % n for n in range(len(sp_args))])),
            bindparams=type_list
        )
        #raise ValueError("%s\n%s" % (sp_call, type_list))
        with database.engine.begin() as connection:
            return connection.execute(
                sp_call,
                # Don't do this at home, kids...
                **dict((str(no), arg)
                    for (no, arg) in zip(range(len(sp_args)), sp_args)))
    except sql.exc.DatabaseError:
        raise

Он работает с синтаксисом CALL, поэтому MySQL должен работать как положено. Я предполагаю, что MSSQL использует EXEC вместо вызова и немного другого синтаксиса. Так что сделать это независимым от сервера - решать вам, но не должно быть слишком сложным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...