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

原创 2015年11月21日 13:32:20

由于需要使用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',''   --不带参

 

版权声明:本文为sam的原创文章,转载请添加出处:http://blog.csdn.net/samed

相关文章推荐

python的django原生sql的实现

当model满足不了需求的时候(比如:存储过程、多表连接等),可以使用原生sql。django提供了两种方法使用原生的sql:你可以使用Manager.raw()执行原生sql,它会返回model实例...

机房收费系统之组合查询的发展过程

下面说下我的组合查询吧。          在组合查询这,最早的想法是用structure,因为印象中有一种类型,是可以用int类型来访问的,可是做的时候发现不是structure,通过在网上查询,...

Python连接数据库-pyodbc

1、连接sql server: conn_info = 'DRIVER={SQL Server};DATABASE=%s;SERVER=%s;UID=%s;PWD=%s'%(database, ho...

python用pyodbc存入SQL SEVER

def save_to_mytsql(result): conn = pyodbc.connect('DRIVER={SQL Server};SERVER=localhost;DATABASE...

SQL Server-- 存储过程中错误处理

一、存储过程中使用事务的简单语法在存储过程中使用事务时非常重要的,使用数据可以保持数据的关联完整性,在Sql server存储过程中使用事务也很简单,用一个例子来说明它的语法格式:Create Pro...
  • fan158
  • fan158
  • 2011年03月17日 10:45
  • 13646

Python如何执行存储过程,获取存储过程返回值

在Pathon中如何执行存储过程呢?可以使用如下方法:存储过程定义基本如下:ALTER  procedure [dbo].[mysp]         @Station varchar(50),   ...
  • andoring
  • andoring
  • 2011年06月23日 23:32
  • 10188

【python 调用储存过程】python 执行储存过程

# -*- coding:utf-8 -*-import sys reload(sys) sys.setdefaultencoding('utf-8') import pymysql conn=pym...

在Python中使用cx_Oracle调用Oracle存储过程

本文主要测试在Python中如何通过cx_Oracle调用PL/SQL Procedure(存储过程)
  • pierre_
  • pierre_
  • 2015年04月13日 16:34
  • 3892

菜鸟学Python(17):用pymssql访问mssql数据库的存储过程

要在linux下用python调用ms sql server的存储过程,google一把,决定使用pymssql。但是文档很少,只有几个最简单的例子。看了网上这个例子后,才明白具体怎么调用存储过程。大...
  • wayne92
  • wayne92
  • 2008年03月05日 18:48
  • 4412

Python3 pexpect自动化测试

Python3 pexpect自动化测试
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:遭瘟的pyodbc——关于存储过程执行
举报原因:
原因补充:

(最多只允许输入30个字)