遭瘟的pyodbc——关于存储过程执行

来源:互联网 发布:淘宝手机单怎么刷步骤 编辑:程序博客网 时间:2024/04/30 08:54

由于需要使用django连接SQL Server,烦人的事情随之而来。

首先Django 没有自带针对MSSQL的BackEnds,所以要自己包装,这个很烦很烦,烦到死了,每次部署到新的机器上都要调试很久。

可以见我之前写的这篇文章:Django连接SQL Server配置指引,其实是可以成功的,但是每次都要配置,太过麻烦了。

而且只能连接一个数据库,如果要连接多个数据库,无法避免要使用pyodbc(或者其它第三方包)来连接。

 

pyodbc,运行Query SQL是不在话下的,非常简单,上面说的文章也有说使用方法:

import pyodbcconnection = pyodbc.connect('DRIVER={SQL Server Native Client 10.0};SERVER=127.0.0.1;DATABASE=DB_name;UID=User_Name;PWD=PassWord')curs = connection.execute('select * from some_table')curs.fetchone()


但是如果要执行存储过程,就痛苦了。

---------------------------------------

冷静一下。

先说说pyodbc的基本用法:

1. 先导入:from pyodbc import connect;

2. 产生连接实例:Conn = connect(DBCONNECTSTR);

3. 产生游标:cur = Conn.cursor();

4. 执行游标命令:cur.execute()、cur.commit()、cur.rollback()之类;

5. 关闭游标:cur.close();

6. 关闭连接实例:Conn.close()。

 

以上6个步骤都是必要的。

当然,如果仅仅是查询,可以直接使用实例直接运行excute命令就可以了,可以不创建游标,那么3、4、5步都可以省略。

上面这些内容网上一大堆教程,我就不多说了。(DRY=Donot Repeat Yourself)

不过网上很多文章都是误导,例如:Python连接数据库-pyodbc

里面说运行存储过程使用 callproc() 方法。

我勒个去,这个方法完全是她YY出来的。

 

提供 connection 和 cursor 的方法列表:

>>> dir(Conn)

['__class__', '__delattr__', '__doc__', '__enter__', '__exit__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'add_output_converter', 'autocommit', 'clear_output_converters', 'close','commit', 'cursor','execute', 'getinfo', 'rollback', 'searchescape', 'timeout']

>>> dir(cur)

['__class__', '__delattr__', '__doc__', '__enter__', '__exit__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__','__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'arraysize','close', 'columns','commit', 'connection', 'description', 'execute', 'executemany', 'fetchall', 'fetchmany','fetchone', 'foreignKeys', 'getTypeInfo', 'next', 'nextset', 'noscan', 'primaryKeys', 'procedureColumns', 'procedures','rollback', 'rowIdColumns', 'rowVerColumns', 'rowcount', 'setinputsizes', 'setoutputsize', 'skip', 'statistics', 'tables']

 

常用的方法和标量我都标记为红色了。

回归正题,执行存储过程用哪个方法呢?不用多想了,还是execute(),然后附加 EXEC 当作SQL命令来执行。

try:    #不关心返回数据存储过程执行方法    cur.execute('EXEC P_THIS_IS_A_PROCDURE param1,param2,%d,%s' %(p3_int,p4_str))    print cur.rowcount  #可以得到存储过程影响的行数    #如果你关心返回值,需要使用这种方式    rows = cur.execute('SET NOCOUNT ON; EXEC P_THIS_IS_A_PROCDURE param1,param2,%d,%s' %(p3_int,p4_str)).fetchall()    print cur.rowcount,rows   #聪明的你已经知道,行数肯定是木有的了(-1),后面的rows是一个列表,看你的数据是咋样的了。    #无论何种方式,都可以最后才commit(其实方式2已经默认包含了commit)    cur.commit()except Exception as e:    print e


上面已经写得比较清楚了,直接执行存储过程就使用EXEC就好了。

如果需要得到返回数据(即存储过程里面有 Select出来的内容),就需要加上SET NOCOUNT ON;参数。参考资料:MSSQL2008 - Pyodbc - Previous SQL was not a query

所以我TMD为了配合pyodbc,存储过程都需要加上一个selet语句,把return值给select出来。

我已经吐了。

变通的方法:

可以写一个外层存储过程,统一调用这个存储过程,把返回值给select出来就好了。

CREATE PROCEDURE P_RUN_PROCDURE_WITH_SELECTRETURN    @I_ProcName NVARCHAR(1000) ,    @I_Params NVARCHAR(1000)AS    DECLARE @SqlStr NVARCHAR(MAX)        /**    * 返回值列表:    * 0  正常退出,存储过程执行成功    * 1  异常退出,参数校验失败    * ……这个随便你写了,主要是和你存储过程里面的return相关    */        SET @SqlStr = 'DECLARE @res INT; EXEC @res = ' + @I_ProcName + ' ' + @I_Params + '; SELECT  @res'    EXEC(@SqlStr)    GO


 调用方法:

EXEC P_RUN_PROCDURE_WITH_SELECTRETURN 'P_DIM_CONSTANT_TOGGLESTATUS','100,''some_string'',123.45'  --带参

EXEC P_RUN_PROCDURE_WITH_SELECTRETURN 'P_DIM_AMB_PATHCREATE',''   --不带参

 

0 0
原创粉丝点击