关闭

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

标签: Pythondjango-pyodbcsql server
1406人阅读 评论(0) 收藏 举报
分类:

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

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

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

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

 

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

import pyodbc

connection = 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

猜你在找
【套餐】Hadoop生态系统零基础入门
【套餐】嵌入式Linux C编程基础
【套餐】2017软考系统集成项目——任铄
【套餐】Android 5.x顶级视频课程——李宁
【套餐】深度学习入门视频课程——唐宇迪
【直播】广义线性模型及其应用——李科
【直播】从0到1 区块链的概念到实践
【直播】计算机视觉原理及实战——屈教授
【直播】机器学习之凸优化——马博士
【直播】机器学习&数据挖掘7周实训--韦玮
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:75330次
    • 积分:1168
    • 等级:
    • 排名:千里之外
    • 原创:41篇
    • 转载:9篇
    • 译文:1篇
    • 评论:9条
    文章分类
    最新评论