在Python语言中,从SQL Server数据库读写数据,通常情况下,都是使用sqlalchemy 包和 pymssql 包的组合,这是因为大多数数据处理程序都需要用到DataFrame对象,它内置了从数据库中读和写数据的函数:read_sql()和to_sql(),这两个函数支持的连接类型是由sqlalchemy和pymssql构成的,因此,掌握这两个包对于查询SQL Server数据库十分必要。

SQLAlchemy的架构

在Python语言环境中,当需要和关系型数据进行交互时,SQLAlchemy是事实上的标准包。SQLAlchemy由两个截然不同的组件组成,称为Core和ORM(Object Relational Mapper,对象关系映射器),Core是功能齐全的数据库工具包,使用SQL 脚本来查询数据库;ORM是基于Core的可选包,把数据库对象抽象成表、列、关系等实体。但是SQLAlchemy本身无法操作数据库,需要pymsql等第三方数据库API(Database API ),简写为 DBAPI,根据数据库类型而调用不同的数据库API。

从上图可以看出,SQLAlchemy的Core组件使用DBAPI来和数据库进行交互,当使用SQL脚本对数据库执行查询和修改操作时,必须用到SQLAlchemy的 Engine 和 Connection 对象。

一,SQLAlchemy的Engine和Connection

使用SQLAlchemy从数据库中读写数据的基本用法:通过SQL 语句更新数据,通过DataFrame的read_sql()函数从数据库中读取数据,通过to_sql()函数把数据写入到数据表中。

1,创建Engine

在对数据库执行读写操作之前,必须连接到数据库。SQLAlchemy通过 create_engine () 函数创建Engine,使用Engine管理DBAPI的连接,DBAPI的连接仅仅表示一种连接资源。应用Engine最有效率的方式是在模块级别创建一次,而不是按照对象或函数来调用。

import pymssql
import sqlalchemy
from sqlalchemy import create_engine connection_format = 'mssql+pymssql://{0}:{1}@{2}/{3}?charset=utf8'
connection_str = connection_format.format(db_user,db_password,db_host,db_name)
engine = create_engine(connection_str,echo=False)

连接字符串的URL格式是:

dialect[+driver]://user:password@host/dbname?charset=utf8

其中,dialect 代表数据库类型,比如 mssql、mysql等,driver 代表DBAPI的类型,比如 psycopg2、pymysql等。

当echo参数为True时,会显示执行的SQL语句,推荐把echo设置False,关闭日记功能。

Engine对象可以直接用于向数据库发送SQL 脚本,调用Engine.execute()函数执行SQL脚本:

2,Engine和Connection

最通用的方法是通过Engine.connect()方法获得连接资源,connection 是Connection的一个实例,是DBAPI连接的一个代理对象。

connection = engine.connect()
result = connection.execute("select username from users")
for row in result:
print("username:", row['username'])
connection.close()

result是ResultProxy的一个实例,该实例引用DBAPI的cursor。如果执行SELECT命令,当把所有的数据行都返回时,ResultProxy将自动关闭DBAPI的游标。如果执行UPDATE命令,不返回任何数据行,在命令执行之后,游标立即释放资源。

当connection显式调用close()函数时,应用的DBAPI 连接会被释放到连接池(connection pool)。

可以使用Engine对象的execute()函数,以一种简单的方式执行上述过程:

result = engine.execute("select username from users")
for row in result:
print("username:", row['username'])

二,显式使用事务

Connection对象提供begin()函数显式开始一个事务(Transaction)对象,该对象通常用于try/except代码块中,以保证调用Transaction.rollback() 或 Transaction.commit()。

connection = engine.connect()
tran = connection.begin()
try:
connection.execute('sql statement')
tran.commit()
except:
tran.rollback()
raise

或者使用上下文管理器编写更简单的代码:

with connection.begin() as tran:
connection.execute('sql statement')

三,自动提交事务

SQLAlchemy 实现了autocommit 功能,在当前没有显式开启事务的情况下,如果SQLAlchemy 检测(Detect)到执行的数据修改命令(比如 INSERT、UPDATE、DELETE)或数据定义命令(比如,CREATE TABLE, ALTER TABLE),那么Connection对象会自动提交事务。

conn = engine.connect()
conn.execute("INSERT INTO users VALUES (1, 'john')") # autocommits

如果设置选项autocommit=True(默认为True),那么检测会自动进行。如果执行的纯文本的SQL语句,并且语句中包含数据修改和数据定义命令,那么自动提交事务。

可以使用Connection.execution_options()方法来设置autocommit选项,实现自动提交的完全控制:

engine.execute(text("SELECT my_mutating_procedure()").execution_options(autocommit=True))

四,执行SELECT查询

使用Engine 或 Connection的execute()函数执行select查询,返回游标变量。游标标量是一个迭代器,每次迭代返回的结果都是一个数据行,数据行是由字段构成的元组:

>>> cursor = engine.execute(' select * from dbo.vic_test')
>>> for row in cursor:
... do_something

也可以使用DataFrame对象的read_sql()函数,把数据读取到DataFrame对象中,或者调用DataFrame对象的to_sql()函数,把DataFrame对象中的数据写入到关系表中。

五,使用原始的DBAPI连接

在某些情况下,SQLAlchemy 无法提供访问某些DBAPI函数的通用方法,例如,调用存储以及处理多个结果集,在这种情况下,直接使用原始DBAPI的连接。

dbapi_conn = engine.raw_connection()

该dbapi_conn是一种代理形式,当调用dbapi的close()方法时,实际上并没有关闭DBAPI的连接,而是把其释放会连接池:

dbapi_conn.close()

例如,使用DBAPI的原始连接来调用存储过程,通过DBAPI级别的callpro()函数来执行存储过程:

connection = engine.raw_connection()
try:
cursor = connection.cursor()
cursor.callproc("my_procedure", ['x', 'y', 'z'])
results = list(cursor.fetchall())
cursor.close()
connection.commit()
finally:
connection.close()

pymssql 包

pymssql包是Python语言用于连接SQL Server数据库的驱动程序(或者称作DBAPI),它是最终和数据库进行交互的工具。SQLAlchemy包就是利用pymssql包实现和SQL Server数据库交互的功能的。

按照惯例,使用pymssql包查询数据库之前,首先创建连接:

import pymssql
conn = pymssql.connect(host='host',database='db_name',user='user',password='pwd',charset='utf8')

通过连接创建游标,通过游标执行SQL语句,查询数据或对数据进行更新操作:

cursor = conn.cursor()
cursor.execute("sql statement") 

如果执行的是修改操作,需要提交事务;如果执行的是查询操作,不需要提交:

conn.commit()

在查询完成之后,关闭连接

conn.close()

六,使用游标查询数据

游标cursor是由连接创建的对象,可以在游标中执行查询,并设置数据返回的格式。

当执行select语句获取数据时,返回的数据行有两种格式:元组和字典,行的默认格式是元组。

cursor = conn.cursor(as_dict=True) 

pymssql返回的数据集的格式是在创建游标时设置的,当参数 as_dict为True时,返回的行是字典格式,该参数的默认值是False,因此,默认的行格式是元组。

由于游标是一个迭代器,因此,可以使用for语句以迭代方式逐行处理查询的结果集。

for row in cursor:

1,以元组方式返回数据行

默认情况下,游标返回的每一个数据行,都是一个元组结构:

cursor=connect.cursor()
cursor.execute('SELECT * FROM persons WHERE salesrep=%s', 'John Doe')
for row in cursor:
print('row = %r' % (row,))

2,以字典方式返回数据行

当设置游标以字典格式返回数据时,每一行都是一个字典结构:

 cursor = conn.cursor(as_dict=True)
cursor.execute('SELECT * FROM persons WHERE salesrep=%s', 'John Doe')
for row in cursor:
print("ID=%d, Name=%s" % (row['id'], row['name']))

七,使用游标更新数据

在执行update、delete或insert命令对数据进行更新时,需要显式提交事务。

1,执行单条语句修改数据

当需要更新数据时,调用游标的execute()函数执行SQL命令来实现,可以以参数化的方式来执行,参数化类似于python的string.format()函数,通过格式化的字符串、占位符和参数来生成TSQL脚本。

cursor.execute(operation)
cursor.execute(operation, params)

通过游标的execute()函数来执行TSQL语句,调用 commit() 来提交事务

cursor.execute("""
sql statement
""")  
conn.commit()

或者以参数化的方式来执行:

cursor.execute("update id=1 FROM persons WHERE salesrep='%s'", 'John Doe')
conn.commit()

2,执行数据的多行插入

如果要在一个事务中执行多条SQL命令,可以调用游标的executemany()函数:

cursor.executemany(operation, params_seq)

如果需要插入多条记录,可以使用游标的executemany()函数,该函数包含模板SQL 命令和一个格式化的参数列表,用于在一条事务中插入多条记录:

args=[(1, 'John Smith', 'John Doe'),
(2, 'Jane Doe', 'Joe Dog'),
(3, 'Mike T.', 'Sarah H.')] cursor.executemany("INSERT INTO persons VALUES (%d, %s, %s)", args )
conn.commit()

八,关闭连接

在一个连接中,用户可以提交多个事务,执行多个操作。当查询完成之后,一定要关闭连接:

conn.close()

通常情况下,使用with来自动关闭连接:

with pymssql.connect(host='host',database='db_name', user='user', password='pwd',charset='utf8') as conn:
with conn.cursor(as_dict=True) as cursor:
cursor.execute('SELECT * FROM persons WHERE salesrep=%s', 'John Doe')
for row in cursor:
print("ID=%d, Name=%s" % (row['id'], row['name']))

九,调用存储过程

从pymssql 2.0.0开始,可以使用callproc函数来执行存储过程,callproc()函数的语法是:

result_args = cursor.callproc(proc_name, args=())

args参数是一个序列,对于存储过程的每一个参数,都需要传递值。对于OUT参数,也必须传递值,通常传递0。

callproc()函数返回的是输入args的修改之后的副本,IN参数在result_args中不变,OUT参数在result_args中代表存储过程输出的值。

举个例子,对于存储add_num,有两个IN参数,一个OUT参数:

CREATE PROCEDURE add_num(IN num1 INT, IN num2 INT, OUT sum INT)

调用callproc()函数的格式是:

result_args = (5, 6, 0) # 0 is to hold value of the OUT parameter sum
cursor.callproc('add_num', result_args)

以下示例代码,使用上下文管理器来调用callproc()执行存储过程:

with pymssql.connect(server, user, password, "tempdb") as conn:
with conn.cursor(as_dict=True) as cursor:
cursor.callproc('sp_name', ('arg1',))
for row in cursor:
print("ID=%d, Name=%s" % (row['id'], row['name']))

参考文档:

Working with Engines and Connections

SQLAlchemy

pymssql introduction

Python中从SQL型数据库读写dataframe型数据

Python 学习 第17篇:从SQL Server数据库读写数据的更多相关文章

  1. 如何用asp.net MVC框架、highChart库从sql server数据库获取数据动态生成柱状图

    如何用asp.net MVC框架.highChart库从sql server数据库获取数据动态生成柱状图?效果大概是这样的,如图: 请问大侠这个这么实现呢?

  2. 01. SQL Server 如何读写数据

    原文:01. SQL Server 如何读写数据 一. 数据读写流程简要SQL Server作为一个关系型数据库,自然也维持了事务的ACID特性,数据库的读写冲突由事务隔离级别控制.无论有没有显示开启 ...

  3. SQL Server 如何读写数据

    01. SQL Server 如何读写数据   一. 数据读写流程简要SQL Server作为一个关系型数据库,自然也维持了事务的ACID特性,数据库的读写冲突由事务隔离级别控制.无论有没有显示开启事 ...

  4. 漫谈可视化Prefuse(一)---从SQL Server数据库读取数据

    上篇<可视化工具solo show-----Prefuse自带例子GraphView讲解>主要介绍了整个Prefuse工具集具有的一些特征.框架的运行流程,分析并展现了官方提供的例子Gra ...

  5. python:利用pymssql模块操作SQL server数据库

    python默认的数据库是 SQLlite,不过它对MySql以及SQL server的支持也可以.这篇博客,介绍下如何在Windows下安装pymssql库并进行连接使用... 环境:Windows ...

  6. SQL Server数据库读取数据的DateReader类及其相关类

    之前学了几天的SQL Server,现在用C#代码连接数据库了. 需要使用C#代码连接数据库,读取数据. 涉及的类有: ConfigurationManage SqlConnection SqlCom ...

  7. Jmeter—8 连接microsoft sql server数据库取数据

    本文以Jmeter 连接microsoft sql server为例. 1 从微软官网下载Microsoft SQL Server JDBC Driver 地址:http://www.microsof ...

  8. SQL Server数据库读写分离提高并发性

    在一些大型的网站或者应用中,单台的SQL Server 服务器可能难以支撑非常大的访问压力.很多人在这时候,第一个想到的就是一个解决性能问题的利器——负载均衡.遗憾的是,SQL Server 的所有版 ...

  9. 用SQL语句将远程SQL Server数据库中表数据导入到本地数据库相应的表中

    一.方法一 访问不同电脑上的数据库(远程访问,只好联好网就一样),如果经常访问或数据量较大,建议用链接服务器方法. 1.创建链接服务器 exec sp_addlinkedserver ‘srv_lnk ...

随机推荐

  1. 微信网站登录doem

    直接上代码 namespace CloudPrj.WeiXin {     public partial class index : System.Web.UI.Page     {         ...

  2. PHP面试题2019年滴滴出行工程师面试题及答案解析

    一.单选题(共30题,每题5分) 1.下列关于PHP垃圾回收的说法,错误的是? A.开启/关闭垃圾回收机制可以通过修改php配置实现 B.可以在程序中使用gc_enable() 和 gc_disabl ...

  3. 面试题-JavaScript交换两个变量的方法

    在平时的业务开发或者面试过程中,经常会遇到交换两个变量这种问题,于是,个人总结以下几种交换变量的方法: 1.方案一 使用一个临时变量来交换  2.方案二 使用ES6解构赋值语法来交换 3.方案三利用数 ...

  4. 一个匹配字字符串是aabbcc或者其他模式的运用

    <!--一个匹配字字符串是aabbcc或aaaabccc或者其他模式的运用--> function isPattern(str, pattern) { let str_a = str.sp ...

  5. TCP/IP协议的分层

    T C P / I P协议族是一组不同的协议组合在一起构成的协议族.尽管通常称该协议族为 T C P / I P,但T C P和I P只是其中的两种协议而已(该协议族的另一个名字是 I n t e r ...

  6. CodeForces - 1007A (思维+双指针)

    题意 https://vjudge.net/problem/CodeForces-1007A 对一个序列重排,使得新的数比原来的数大对应的位置个数最多. 思路 举个栗子,比如1 2 2 3 3 3 3 ...

  7. postman---postman增加断言

    我们在做测试的时候都会有一个验证点,我们通常把这个验证点叫做断言,断言通过了就会说明我们的这个用例是通过的,当然这么强大的postman也是有断言的,我们一起学习下如何通过postman增加断言. 断 ...

  8. 扎西平措 201571030332 《面向对象程序设计(java)课程学习进度条》

    <2019面向对象程序设计(java)课程学习进度条> 周次 (阅读/编写)代码行数 发布博客量/评论他人博客数量 课余学习时间(小时) 学习收获最大的程序 阅读或编译让我 第一周 20/ ...

  9. day65_10_9vue循环指令与组件

    一.v-once v-once指令赋值给标签后,这个标签中的所有变量都不能被更改,只能被渲染一次.之后的改动不能改变该标签中的值: <div id="app"> < ...

  10. Django的下载与创建。

    一.下载 (1)下载命令. 在cmd中输入下载命令: pip3 install django==1.11.11 1.11.11是该版本号. (2)pycharm中下载 直接在pycharm中下载set ...