数学建模社区-数学中国

标题: pyodbc的简单使用 [打印本页]

作者: Seawind2012    时间: 2012-7-4 14:30
标题: pyodbc的简单使用
1、连接数据库
$ Y) q7 P, B- b! D$ j( p* Z' K' E% h& z& O8 `* I1 f' y
1)直接连接数据库和创建一个游标(cursor), d7 l7 t, g! r7 z
1        cnxn = pyodbc.connect('DRIVER={SQL Server};SERVER=localhost;DATABASE=testdb;UID=meWD=pass')
, p5 h7 M1 Q$ k2        cursor = cnxn.cursor()* w* [0 Z6 W- W9 P$ ~
/ a/ L' x; ?: g+ y$ y
2)使用DSN连接。通常DSN连接并不需要密码,还是需要提供一个PSW的关键字。+ ?6 P, ?8 v  H( V% R
1        cnxn = pyodbc.connect('DSN=testWD=password')
8 |: t4 p8 i: S8 A, j: i0 n2        cursor = cnxn.cursor()4 w  @) j! ~3 M
1 g( l# o! D$ k4 e/ q; D3 S
关于连接函数还有更多的选项,可以在pyodbc文档中的 connect funtion 和 ConnectionStrings查看更多的细节
, r* P4 U& ?* ~' L  W1 ~9 v* h* q/ x: J+ w9 P3 E
2、数据查询(SQL语句为 select ...from..where)
" J0 w- v( [) z
1 P7 H  O# j4 Q- \3 x  N; M1)所有的SQL语句都用cursor.execute函数运行。如果语句返回行,比如一个查询语句返回的行,你可以通过游标的fetch函数来获取数据,这些函数有(fetchone,fetchall,fetchmany).如果返回空行,fetchone函数将返回None,而fetchall和fetchmany将返回一个空列。$ e6 N6 `% U; `- ^
1        cursor.execute("select user_id, user_name from users")+ O* v0 F4 }1 Y3 s9 p, o0 J
2        row = cursor.fetchone()
* L& {* y6 ^" A) B7 h1 @5 }3        if row:. m- m' t1 s1 [6 p4 b& H
4            print row% V5 u, A0 b* r
( m/ ?1 X" ]  s3 h, p' O
2)Row这个类,类似于一个元组,但是他们也可以通过字段名进行访问。' }$ [) X, p! D6 S5 i! W
1        cursor.execute("select user_id, user_name from users")/ _4 B# s! K* K8 l
2        row = cursor.fetchone()3 d, L1 D5 S3 W+ i. W
3        print 'name:', row[1]          # access by column index9 B/ M6 ?& [. N
4        print 'name:', row.user_name   # or access by name
% G' t3 e- J" Q, G, K0 R5 ^4 C8 ]
3)如果所有的行都被检索完,那么fetchone将返回None.
/ a3 _4 J- W; W7 K7 A' y1        while 1:  C* q* }* g' x2 D7 V6 z/ }7 Q
2            row = cursor.fetchone()5 s5 k' t$ [1 m. z/ T) g
3            if not row:  f1 |  c$ ?6 m$ J
4                break
5 ^! b/ K. `8 \) ~9 m2 a5            print 'id:', row.user_id
6 I6 y8 a# ~7 }7 j3 c0 u
2 |5 \& U$ z' w3 N. _4)使用fetchall函数时,将返回所有剩下的行,如果是空行,那么将返回一个空列。(如果有很多行,这样做的话将会占用很多内存。未读取的行将会被压缩存放在数据库引擎中,然后由数据库服务器分批发送。一次只读取你需要的行,将会大大节省内存空间)
3 Y! G" k( U, X1        cursor.execute("select user_id, user_name from users")
& r( ~" G, b$ Y: _! \2        rows = cursor.fetchall(). c) ]- b/ a& c7 u5 C, b0 Q
3        for row in rows:
/ ^7 r" A" [8 I$ I% |  z4            print row.user_id, row.user_name/ \1 ]0 o  T( C, e0 ^! s3 U5 K! @
0 N2 M! `) w6 i) {4 t
5)如果你打算一次读完所有数据,那么你可以使用cursor本身。9 ]+ l8 n% q8 h: ^2 i
1        cursor.execute("select user_id, user_name from users"):
# {# C( Q4 @! e+ Q  g& x$ @4 J2        for row in cursor:
5 m/ `, u. \! t4 N7 J( V3            print row.user_id, row.user_name+ g% j1 ~. ?( s3 Q3 K$ h- S
" P, h, Y: B; h! n* M/ }7 ], o
6)由于cursor.execute返回一个cursor,所以你可以把上面的语句简化成:7 o+ {0 s6 ~! T( U% g8 p! Z" t
1        for row in cursor.execute("select user_id, user_name from users"):) J7 |9 N8 I5 j( U
2            print row.user_id, row.user_name1 `+ k6 J) S& u7 I
% F! J' b- W/ N* ^: C$ ^) Q
7)有很多SQL语句用单行来写并不是很方便,所以你也可以使用三引号的字符串来写:
' z0 O4 |  Z9 s: o: H- _5 J8 t! ?7 u1        cursor.execute("""
0 F, K6 r& B: r/ c* Q2                       select user_id, user_name
% ^8 `* G1 E+ ^. ^3                         from users4 p% n) m) A$ O4 P
4                        where last_logon < '2001-01-01'
8 {. r. z% f0 q+ J+ N; X9 I& F+ [5                          and bill_overdue = 'y', g4 G8 Y1 W, k
6                       """)
" X, X# A, F) y4 D: H, |$ |& s5 W: ]+ O5 a5 E
3、参数) \9 m! C% }& [6 r* a/ ]# m; H( n* A$ U
; X( v/ M+ _# W7 T1 a  c5 Z
1)ODBC支持在SQL语句中使用一个问号来作为参数。你可以在SQL语句后面加上值,用来传递给SQL语句中的问号。" M1 ?5 {% i0 N8 z; g
1        cursor.execute("""
8 U" G" R/ \/ L; f' ^6 O2                       select user_id, user_name) L  d8 }$ e* H9 L- r
3                         from users8 \. n% R0 t5 P% w+ ]8 K/ |
4                        where last_logon < ?! ~9 @5 Q5 n, M  [' l! S9 n5 D
5                          and bill_overdue = ?
2 h6 p; ], T; J3 n) p( A0 p6                       """, '2001-01-01', 'y')
4 y, z% k: l2 {; R7 m3 r, Q2 h$ r, @2 ]5 L
这样做比直接把值写在SQL语句中更加安全,这是因为每个参数传递给数据库都是单独进行的。如果你使用不同的参数而运行同样的SQL语句,这样做也更加效率。
6 s+ F+ _; N* H! G
2 t4 G- V7 E8 I. \) u3)python DB API明确说明多参数时可以使用一个序列来传递。pyodbc同样支持:
0 l& {# x! j* }0 K! d, ^- i1        cursor.execute("""
9 V9 N2 t  F6 H  ]2                       select user_id, user_name
; r. U' D9 N, H4 h8 V! P, w3                         from users
  m+ \+ D/ K% k% W, e0 j: q4                        where last_logon < ?2 m% b* q0 E* ^
5                          and bill_overdue = ?
& N3 B& T: p+ Z2 \2 B" D$ B+ |6                       """, ['2001-01-01', 'y'])/ q8 L' [; ^% j* G. @
0 H! o. c7 o% O
1        cursor.execute("select count(*) as user_count from users where age > ?", 21)
% j- D' Y% p, e2 l# F2        row = cursor.fetchone()
# }, a3 [+ }; o4 t; X3        print '%d users' % row.user_count
$ i8 [# S+ u) E/ M. p/ V: K9 _" k: R* E6 l
/ V2 I+ T0 Q. G0 d  w& T! j
9 [0 G& S8 @! p
4、数据插入( @! U2 j' w) _; C) T% w
* `$ g8 H8 M/ l* J  J$ T
1)数据插入,把SQL插入语句传递给cursor的execute函数,可以伴随任何需要的参数。0 c7 m6 r3 U* K* |, }
1        cursor.execute("insert into products(id, name) values ('pyodbc', 'awesome library')")( B6 ?: J& V6 h$ o' O
2        cnxn.commit()
% K, O- O* Z" @  v% [9 q3 S" l+ F1 \, i& t3 T4 ^
1        cursor.execute("insert into products(id, name) values (?, ?)", 'pyodbc', 'awesome library')/ f) H) h; h" {9 r+ B  d3 U4 c
2        cnxn.commit(); S7 _7 @, \4 q
% Z; L; {# c  Z) n6 `* }4 _
注意调用cnxn.commit()函数:你必须调用commit函数,否者你对数据库的所有操作将会失效!当断开连接时,所有悬挂的修改将会被重置。这很容易导致出错,所以你必须记得调用commit函数。1 `+ Z3 P4 V  {- J" E7 O
% A3 V1 t& I6 w0 {- l
5、数据修改和删除
: @' j' l  Q4 o- R- x$ _" S+ T
- a# P: B+ @, K% O  \1)数据修改和删除也是跟上面的操作一样,把SQL语句传递给execute函数。但是我们常常想知道数据修改和删除时,到底影响了多少条记录,这个时候你可以使用cursor.rowcount的返回值。
& R& s- z* y: B. o9 T2 [3 v1        cursor.execute("delete from products where id <> ?", 'pyodbc')
) p' P9 y8 u1 `8 `- i" h) {3 {' R% k2        print cursor.rowcount, 'products deleted'
# b$ ~# D" D6 E! x6 a3 \0 p3        cnxn.commit()' S, B! |  d$ R' c' Q

! p8 E9 J1 W- z4 ?' y1 O$ U' Y2)由于execute函数总是返回cursor,所以有时候你也可以看到像这样的语句:(注意rowcount放在最后面)$ m0 K  O& l" |: O! `% i9 s
1        deleted = cursor.execute("delete from products where id <> 'pyodbc'").rowcount/ O9 }5 W2 w7 j% X. q
2        cnxn.commit()
3 R) p' E. P" }) @7 D9 ~# J" L' S: J' y; g% H* b
同样要注意调用cnxn.commit()函数
# i# @% g0 }" l; H% G$ m, ~7 J! A6 k# F: V- O5 F
6、小窍门$ E( K# c3 I8 t& o

* c# k$ m% q! i6 T1)由于使用单引号的SQL语句是有效的,那么双引号也同样是有效的:# |, \! z# d& T! n# ?6 @
1        deleted = cursor.execute("delete from products where id <> 'pyodbc'").rowcount
) P: Y8 R& P& q# @+ m, {7 P
+ `8 O! J3 ]& k" v2)假如你使用的是三引号,那么你也可以这样使用:
1 O1 ^# o- S' H. F$ B3 |1        deleted = cursor.execute("""9 z' r) \) M# l/ s
2                                 delete* t- I4 @$ v2 H( \  w6 `/ {
3                                   from products
/ y6 i; P1 u  U* k+ r, ?, y4                                  where id <> 'pyodbc'
$ G' ]) p; y6 I, R) U5                                 """).rowcount$ Y5 ?2 q( }0 S( ?. s0 ]& w9 @
2 y. D3 b# v  U5 x( Z; H2 h1 E
3)有些数据库(比如SQL Server)在计数时并没有产生列名,这种情况下,你想访问数据就必须使用下标。当然你也可以使用“as”关键字来取个列名(下面SQL语句的“as name-count”)6 M5 t5 l, [* m- i+ d
1        row = cursor.execute("select count(*) as user_count from users").fetchone()
+ O% t! o$ R" M2        print '%s users' % row.user_count
& r+ F0 P0 x7 Z  ~( x7 z4 p9 q6 k) @) x# K  Q
4)假如你只是需要一个值,那么你可以在同一个行局中使用fetch函数来获取行和第一个列的所有数据。
3 ]1 o3 @* J0 P2 J1        count = cursor.execute("select count(*) from users").fetchone()[0]
1 O! [, c) R9 ]" S  Q! b5 L2        print '%s users' % count
. \8 e, B! i. d2 @' g" T5 b$ U  V1 Z" x2 d5 e( O! B( U, f9 ?% ]
如果列为空,将会导致该语句不能运行。fetchone()函数返回None,而你将会获取一个错误:NoneType不支持下标。如果有一个默认值,你能常常使用ISNULL,或者在SQL数据库直接合并NULLs来覆盖掉默认值。" g3 Z; u& [/ e3 L) K% _" j, q
1        maxid = cursor.execute("select coalesce(max(id), 0) from users").fetchone()[0]/ @. N5 s. l, C" _# m; t

8 v0 w7 G) g7 J3 x* c+ n在这个例子里面,如果max(id)返回NULL,coalesce(max(id),0)将导致查询的值为0。




欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5