2010-08-25 98 views

回答

15

引擎和連接有一個​​方法可以用於任意的sql語句,Sessions也是如此。例如:

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

您可以使用outparam()創建輸出參數,如果你需要(或綁定參數使用bindparam()isoutparam=True選項)

+0

這不是數據庫不可知的。改用'sqlalchemy.sql.text'。 – Profpatsch 2013-10-22 14:38:22

+0

順便說一句,如果你想訪問MS SQL Server中存儲過程返回的行,你需要'sess.execute('SET NOCOUNT ON')'。您可以在一個執行調用中執行該操作:'results = sess.execute('SET NOCOUNT ON; EXEC myproc?,?; SET NOCOUNT OFF',[param1,param2])'。 – 2016-03-21 13:46:18

+1

這是一箇舊的線程,所以也許這是在sqlalchemy的新版本中已經改變的東西,但我必須使用字典而不是參數列表,並在原始sql中使用「:param_name」而不是「?」 。因此,上面的例子變成:'sess.execute('myproc:p1,:p2',{'p1':'value1','p2':'value2'})' – ThatAintWorking 2016-06-29 20:28:08

6

只需執行與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

這不適用於MySQL,'Function不存在。' – Profpatsch 2013-10-22 12:15:10

+0

爲我工作,優雅和簡單的方式來調用存儲過程。官方說明_:數據:'.func'構造只有有限的支持調用 獨立的「存儲過程」,特別是那些有特殊 參數化問題。 見:參考:'stored_procedures'有關如何使用 的DBAPI級''callproc細節()''方法完全傳統的存儲 procedures._ 代碼爲我這樣的人:'session.execute( FUNC。your_proc_name(param1,param2))' – Niyojan 2016-07-12 08:37:14

5

假設您已經使用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

這看起來很容易受到SQL注入的影響。 – 2016-03-21 13:46:58

+0

這確實很脆弱。用'execute(sql_string,params = ...)'傳遞命名參數以讓引擎轉義參數值更好。 @Profpatsch的答案已經做到了。 – 2016-06-01 12:25:07

+0

我該如何收集輸出參數?即,我的聲明是: 'EXEC dbo.next_rowid'dbo','workorder_feature',@id OUTPUT;'我如何獲得ID? – roemhildtg 2017-03-21 14:15:14

1

出於迫切需要爲我的項目,我寫了一個處理存儲過程調用的函數。

在這裏你去:

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而不是調用和一些不同的語法。因此,使其成爲服務器不可知論取決於你,但不應該太難。

3

使用SQLAlchemy在MySQL中調用存儲過程的最簡單方法是使用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()