2010-08-25 3 views

risposta

15

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)

+0

Questo non è indipendente dal database. Utilizzare invece 'sqlalchemy.sql.text'. – Profpatsch

+0

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])'. –

+1

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

6

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 
+0

Questo non funziona con MySQL, 'Funzione non esiste. – Profpatsch

+0

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

5

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) 
+5

Questo sembra vulnerabile all'iniezione SQL. –

+0

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à. –

+0

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

1

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.

3

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()