pyodbc文档之 Getting started(开始使用)

Connect to a Database(连接到数据库)

传递一个 ODBC连接字符串给pyodbc connect()函数,函数将返回一个 Connection. 有了connection 之后,你就可以创建Cursor.(游标),就像下面这样:

import pyodbc

# Specifying the ODBC driver, server name, database, etc. directly
cnxn = pyodbc.connect('DRIVER={SQL Server};SERVER=localhost;DATABASE=testdb;UID=me;PWD=pass')

# Using a DSN, but providing a password as well
cnxn = pyodbc.connect('DSN=test;PWD=password')

# Create a cursor from the connection
cursor = cnxn.cursor()

当建立连接的时候,有许多的选项,详情参见 connect()函数 以及 the Connecting to Databases 这一节。

确保你设置了正确的你所连接的数据库所要求的编码或解码设置 ,以及使用适合的Python版本:

# This is just an example that works for PostgreSQL and MySQL, with Python 2.7.
cnxn.setdecoding(pyodbc.SQL_CHAR, encoding='utf-8')
cnxn.setdecoding(pyodbc.SQL_WCHAR, encoding='utf-8')
cnxn.setencoding(encoding='utf-8')

Selecting Some Data(选择一些数据)

Select Basics

所有的SQl语句都是用Cursor()函数(游标)执行。如果语句返回的是行的集合,比如select语句,你可以使用Cursor 的 fetch函数 - fetchone(), fetchall(), fetchmany()。如果返回的结果没有行, fetchone() 会返回 None,但是 fetchall() 和 fetchmany() 都会返回空的列表(list)。

cursor.execute("select user_id, user_name from users")
row = cursor.fetchone()
if row:
    print(row)

Row objects are similar to tuples, but they also allow access to columns by name:
行对象和元组很类似,但是它们允许通过列名获取:

cursor.execute("select user_id, user_name from users")
row = cursor.fetchone()
print('name:', row[1])          # 通过下标访问 access by column index (zero-based)
print('name:', row.user_name)   # 通过列名访问 access by name

当检索完所有的行后, fetchone() 函数返回None。

while True:
    row = cursor.fetchone()
    if not row:
        break
    print('id:', row.user_id)

fetchall()函数返回一个列表中的所有剩余行。记住,这些行将全部存储在内存中,所以如果有很多行,则可能内存不足。如果没有行,则返回空列表。

cursor.execute("select user_id, user_name from users")
rows = cursor.fetchall()
for row in rows:
    print(row.user_id, row.user_name)

如果要一次处理一行,可以使用游标本身作为迭代器:

cursor.execute("select user_id, user_name from users"):
for row in cursor:
    print(row.user_id, row.user_name)

或者这样子:

for row in cursor.execute("select user_id, user_name from users"):
    print(row.user_id, row.user_name)

Parameters(参数)

ODBC支持在SQL中使用问号来为参数占位。并在紧随SQL语句之后将问号替换为具体的值:

cursor.execute("""
    select user_id, user_name
      from users
     where last_logon < ?
       and bill_overdue = ?
""", datetime.date(2001, 1, 1), 'y')

这比将值放入字符串更安全,因为参数分别传递到数据库,以防止SQL注入攻击。如果用不同的参数重复执行相同的SQL语句,则效率也会更高。SQL语句只会在数据库中编译一次。(pyodbc 只保留最后一次编译的SQL语句,所以如果你执行不同的SQL语句,那么每个语句会被多次重新编译(亦即每次执行都会重新编译)。)

Python DB API指定参数应该作为一个序列传递,在pyodbc中也同样支持:

cursor.execute("""
    select user_id, user_name
      from users
     where last_logon < ?
       and bill_overdue = ?
""", [datetime.date(2001, 1, 1), 'y'])

Inserting Data(插入数据)

若要插入数据,请将插入SQL语句传递给 Cursor execute(),以及需要的参数。

cursor.execute("insert into products(id, name) values ('pyodbc', 'awesome library')")
cnxn.commit()

或者,参数化查询:

cursor.execute("insert into products(id, name) values (?, ?)", 'pyodbc', 'awesome library')
cnxn.commit()

注意此处的调用 cnxn.commit()。你必须调用commit (或者在connection中设置 autocommit 为 True ) ,否则你的查询不会被执行(数据库不会有改变)。

Updating and Deleting(更新和删除)

更新和删除的方法都是一样的。然而,如果希望知道在更新和删除数据时有多少条数据(记录)受影响,在这种情况下,您可以使用Cursor( 游标)的 rowcount(行计数)属性:

cursor.execute("delete from products where id <> ?", 'pyodbc')
print(cursor.rowcount, 'products deleted')
cnxn.commit()

因为 execute() 通常返回 cursor(游标),你有时会看到这样的代码 (游标执行 .rowcount(末尾)).

deleted = cursor.execute("delete from products where id <> 'pyodbc'").rowcount
cnxn.commit()

注意调用commit() (示例代码中的 cnxn.commit() )。你必须调用commit (或者在connection中设置 autocommit(自动提交 )为 True ) ,否则你的语句不会生效(被数据库执行)!

Tips and Tricks(技巧和提示)

Quotes(引号的使用)

因为在SQL中,单引号是合法的,使用双引号把SQl语句包围起来:

deleted = cursor.execute("delete from products where id <> 'pyodbc'").rowcount

使用“原始”字符串来避免SQL无意中的转义(除非你真的想要指定转义字符):

cursor.execute("delete from products where name like '%bad\name%'")   #Python会将 \n 转义为 换行 
cursor.execute(r"delete from products where name like '%bad\name%'")  # 不会转换,保留完整的原始字符串

Naming Columns(列命名)

一些数据库(例如:SQL Server)不会为 聚合函数 所生成的字段(列)命名,例如:COUNT(*),在这种情况下,您可以通过它的索引访问列,或者在列上使用别名(即使用“AS”关键字进行命名)。

row = cursor.execute("select count(*) as user_count from users").fetchone()
print('%s users' % row.user_count)

Formatting Long SQL Statements(格式化长SQL语句)

有许多方法去格式化一个包含长SQl语句的Python字符串。使用triple-quote string format(直译:三重引用字符串格式)是显而易见的方法(译注:可以直接搜索 格式化SQL 就有许多在线格式化网站可以选择)。
这样做会在左侧创建大量空白的字符串(空格),但是数据库SQL引擎会忽略空白(包括tabs和换行)。如果你一定要移除这些空白,你可以使用内置的 textwrap 模块中的 dedent() 函数。例如:

import textwrap
. . .
sql = textwrap.dedent("""
    select p.date_of_birth,
           p.email,
           a.city
    from person as p
    left outer join address as a on a.address_id = p.address_id
    where p.status = 'active'
      and p.name = ?
""")
rows = cursor.execute(sql, 'John Smith').fetchall()

fetchval(fetchval函数)

如果你查询的是一个值(单个值,而非一条记录),你可以使用一个非常方便的方法(函数)fetchval
如果SQL语句得到的结果是行(记录的形式),返回第一行的第一列的值。如果没有行(记录),返回None:

maxid = cursor.execute("select max(id) from users").fetchval()

大多数数据库支持 COALESCE 或 ISNULL ,能够把NULL转换为hardcoded value(硬编码值),但是,如果执行结果没有返回任何行的话,这个函数也不会返回任何行。这也就是说,COALESCE是非常有用的聚合函数,如max或count,但是当试图从特定行检索值时,fetchval更好:

cursor.execute("select coalesce(max(id), 0) from users").fetchone()[0]
cursor.execute("select coalesce(count(*), 0) from users").fetchone()[0]

在语句能够返回一个空集的情况下,fetchval则是绝佳的选择:

# Careful!
cursor.execute(
    """
    select create_timestamp
    from photos
    where user_id = 1
    order by create_timestamp desc
    limit 1
    """).fetchone()[0]

# Preferred
cursor.execute(
    """
    select max(updatetime), 0)
    from photos
    where user = 1
    order by create_timestamp desc
    limit 1
    """).fetchval()

第一个示例中,如果没有任何行有user_id 1,将引发异常。调用 fetchone() 返回 None.然后,Python会尝试对无效的结果进行[0]为索引的访问 (None[0]) .即引发异常。
fetchval 是为这种情况而创建的,它检测到没有符合条件的行,然后返回None。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,980评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,422评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,130评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,553评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,408评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,326评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,720评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,373评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,678评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,722评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,486评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,335评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,738评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,283评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,692评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,893评论 2 335

推荐阅读更多精彩内容

  • Python 面向对象Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对...
    顺毛阅读 4,203评论 4 16
  • pyspark.sql module Module context Spark SQL和DataFrames中的重...
    盗梦者_56f2阅读 5,400评论 0 19
  • 这是一个三线小城,有着深厚却和老百姓生活联系不怎么紧密的文化底蕴。日出而作,按部就班。也许日子本该这么不动声色的平...
    楠哥说的对阅读 918评论 3 49
  • 素麻坊阅读 365评论 2 2
  • 夜已深 星星睡了 寥寥几个眨巴着眼 所有路灯熄灭了 所有窗户昏暗了 思绪漫延在无边的夜色里 枕头压扁抱在胸口 散发...
    一树丁香阅读 344评论 8 27