How can I call stored procedures of sql server with sqlAlchemy?
8 Answers
Engines and Connections have an execute()
method you can use for arbitrary sql statements, and so do Sessions. For example:
results = sess.execute('myproc ?, ?', [param1, param2])
You can use outparam()
to create output parameters if you need to (or for bind parameters use bindparam()
with the isoutparam=True
option)

- 28,002
- 5
- 61
- 51
-
3This is not database-agnostic. Use `sqlalchemy.sql.text` instead. – Profpatsch Oct 22 '13 at 14:38
-
3BTW you need to `sess.execute('SET NOCOUNT ON')` if you want to access the rows returned by the stored procedure in MS SQL Server. You can do that in one execute call: `results = sess.execute('SET NOCOUNT ON; EXEC myproc ?, ?; SET NOCOUNT OFF', [param1, param2])`. – Marius Gedminas Mar 21 '16 at 13:46
-
5This is an old thread so, maybe this is something that has changed in newer versions of sqlalchemy, but I had to use a dictionary instead of a list for the parameters and use ":param_name" in the raw sql instead of "?". So, the example above becomes: `sess.execute('myproc :p1, :p2', {'p1': 'value1', 'p2': 'value2'})` – ThatAintWorking Jun 29 '16 at 20:28
-
Also check Denis Otkidach answer(and comments part) – Niyojan Jul 12 '16 at 08:42
-
We had a case where the run in a standard connection failed, but succeeded when run in a transaction: `with engine.begin() as conn: ...` – Thomas Andrews May 03 '17 at 20:40
-
@Steven how can we use output param ? Example, stmt.bindparams(bindparam("isTrue", type_=bool, isoutparam=True)) result = conn.execute(stmt, { 'id': mydata.id, 'name': mydata.name}) How to add output param in result? – user14806829 Oct 12 '21 at 23:43
context: I use flask-sqlalchemy with MySQL and without ORM-mapping. Usually, I use:
# in the init method
_db = SqlAlchemy(app)
#... somewhere in my code ...
_db.session.execute(query)
Calling stored procedures is not supported out of the box: the callproc
is not generic, but specific to the mysql connector.
For stored procedures without out params, it is possible to execute a query like
_db.session.execute(sqlalchemy.text("CALL my_proc(:param)"), param='something')
as usual. Things get more complicated when you have out params...
One way to use out params is to access the underlying connector is through engine.raw_connection()
. For example:
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>)
This is nice since we are able to access the out parameter, BUT this connection is not managed by the flask session. This means that it won't be committed/aborted as with the other managed queries... (problematic only if your procedure has side-effect).
Finally, I ended up doing this:
# 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()
The result
will be a tuple with one value: the out param. This is not ideal, but the least dangerous: if another query fails during the session, the procedure call will be aborted (rollback) as well.

- 9,572
- 2
- 32
- 53
The easiest way to call a stored procedure in MySQL using SQLAlchemy is by using callproc
method of Engine.raw_connection()
. call_proc
will require the procedure name and parameters required for the stored procedure being called.
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()

- 149
- 2
- 5
-
It works for more than MySQL. I can personally confirm that Postgres works out of the box as well. See the official SQL Alchemy docs supporting this answer: https://docs.sqlalchemy.org/en/13/core/connections.html – David Maddox Feb 18 '20 at 03:17
-
Is it possible to map results to the ORM class and use it with the where clause? – Ievgen Mar 25 '21 at 11:19
Just execute procedure object created with 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

- 32,032
- 8
- 79
- 100
-
Worked for me, Elegant and simple way to call stored procedures.Official notes _The :data:`.func` construct has only limited support for calling standalone "stored procedures", especially those with special parameterization concerns. See the section :ref:`stored_procedures` for details on how to use the DBAPI-level ``callproc()`` method for fully traditional stored procedures._ Code for people like me :`session.execute(func.your_proc_name(param1, param2))` – Niyojan Jul 12 '16 at 08:37
-
2Does this work for user-generated stored procedures? I am getting an error that my function is not a built-in procedure. – Steve Scott Jan 15 '21 at 19:21
Supposing you already have session created with sessionmaker(), you can use following function:
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()
Now you can execute your stored procedure 'MyProc' with parameters simply like that:
params = {
'Foo': foo_value,
'Bar': bar_value
}
exec_procedure(session, 'MyProc', params)

- 139
- 1
- 2
-
11
-
This indeed is vulnerable. It is better to pass named arguments with `execute(sql_string, params=...)` to let the engine escape the argument values. The answer by @Profpatsch does that already. – Stefan Dragnev Jun 01 '16 at 12:25
-
1How would I collect an output parameter with this? ie, my statement is: `EXEC dbo.next_rowid 'dbo', 'workorder_feature', @id OUTPUT;` how do I get the id? – twoLeftFeet Mar 21 '17 at 14:15
Out of desperate need for a project of mine, I wrote a function that handles Stored Procedure calls.
Here you go:
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
It works with the CALL syntax, so MySQL should work as expected. MSSQL uses EXEC instead of call and a little differennt syntax, I guess. So making it server agnostic is up to you but shouldn’t be too hard.

- 4,918
- 5
- 27
- 32
Another workaround:
query = f'call Procedure ("{@param1}", "{@param2}", "{@param3}")'
sqlEngine = sqlalchemy.create_engine(jdbc)
conn = sqlEngine.connect()
df = pd.read_sql(query,conn,index_col=None)

- 1,990
- 16
- 22

- 25
- 2
I had a stored procedure for postgresql with following signature -
CREATE OR REPLACE PROCEDURE inc_run_count(
_host text,
_org text,
_repo text,
_rule_ids text[]
)
After quite a few error and trial, I found this is how to call the procedure from python3.
def update_db_rule_count(rule_ids: List[str], host: str, org: str, repo: str):
param_dict = {"host": host, "org": org, "repo": repo, "rule_ids": f'{{ {",".join(rule_ids)} }}'}
with sessionmaker(autocommit=False, autoflush=False, bind=ro_engine) as analytics_db:
analytics_db.execute('call inc_run_count(:host, :org, :repo, :rule_ids)', param_dict)
analytics_db.commit()

- 935
- 9
- 16