Come posso chiamare stored procedure di sql server con sqlAlchemy?stored procedure con sqlAlchemy
risposta
I motori e i collegamenti hanno un metodo execute()
che è possibile utilizzare per istruzioni arbitrarie di SQL, e quindi anche Sessioni. Per esempio:
results = sess.execute('myproc ?, ?', [param1, param2])
È possibile utilizzare outparam()
per creare parametri di output se è necessario (o per i parametri legano utilizzano bindparam()
con l'opzione isoutparam=True
)
Basta eseguire oggetto procedura creata con 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
Questo non funziona con MySQL, 'Funzione non esiste. – Profpatsch
Ha funzionato per me, un modo elegante e semplice per chiamare stored procedure. Note ufficiali _Il dato: il costrutto '.func' ha un supporto limitato per chiamare le" stored procedure "standalone , specialmente quelle con problemi di parametrizzazione speciali . Vedi la sezione: ref: 'stored_procedures' per i dettagli su come utilizzare il DBAPI livello' 'callproc()' 'per pienamente tradizionale memorizzato procedures._ Codice per le persone come me:' session.execute (func.your_proc_name (param1, param2)) ' – Niyojan
Supponendo di aver già creato una sessione con sessionmaker(), è possibile utilizzare la seguente funzione:
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()
Ora è possibile eseguire il procedimento 'MyProc' memorizzato con i parametri semplicemente così:
params = {
'Foo': foo_value,
'Bar': bar_value
}
exec_procedure(session, 'MyProc', params)
Questo sembra vulnerabile all'iniezione SQL. –
Questo è davvero vulnerabile. È meglio passare argomenti con nome con 'execute (sql_string, params = ...)' per lasciare che il motore sfugga ai valori degli argomenti. La risposta di @Profpatsch lo fa già. –
Come posso raccogliere un parametro di output con questo? cioè, la mia affermazione è: 'EXEC dbo.next_rowid 'dbo', 'workorder_feature', @id OUTPUT;' come ottengo l'id? – roemhildtg
Fuori disperato bisogno di un mio progetto, ho scritto una funzione che gestisce Stored Procedure Calls.
Qui si va:
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
Funziona con la sintassi CALL, quindi MySQL dovrebbe funzionare come previsto. MSSQL usa EXEC al posto della chiamata e una sintassi leggermente diversa, suppongo. Quindi renderlo agnostico da server dipende da te, ma non dovrebbe essere troppo difficile.
Il modo più semplice per chiamare una stored procedure in MySQL utilizzando SQLAlchemy è utilizzando il metodo di Engine.raw_connection()
. call_proc
richiederà il nome della procedura e i parametri richiesti per la chiamata alla procedura memorizzata.
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()
Questo non è indipendente dal database. Utilizzare invece 'sqlalchemy.sql.text'. – Profpatsch
BTW è necessario 'sess.execute ('SET NOCOUNT ON')' se si desidera accedere alle righe restituite dalla stored procedure in MS SQL Server. È possibile farlo in una chiamata execute: 'results = sess.execute ('SET NOCOUNT ON; EXEC myproc?,?; SET NOCOUNT OFF', [param1, param2])'. –
Questa è una vecchia discussione quindi, forse è qualcosa che è cambiato nelle versioni più recenti di sqlalchemy, ma ho dovuto usare un dizionario invece di una lista per i parametri e usare ": param_name" nel raw sql invece di "?" . Quindi, l'esempio sopra diventa: 'sess.execute ('myproc: p1,: p2', {'p1': 'value1', 'p2': 'value2'})' – ThatAintWorking