数学建模社区-数学中国

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

作者: Seawind2012    时间: 2012-7-4 14:30
标题: pyodbc的简单使用
1、连接数据库9 U4 u( F: k/ J) G: p7 Y
9 g( x$ v* @4 f: O
1)直接连接数据库和创建一个游标(cursor)
& v1 q  }; a- \9 y! Z1        cnxn = pyodbc.connect('DRIVER={SQL Server};SERVER=localhost;DATABASE=testdb;UID=meWD=pass')+ F( p6 ~- Q2 q- Y4 {& s
2        cursor = cnxn.cursor()
" s9 _7 T& O( o: }( u) n! T  [. H2 R0 k1 }; u: B! H. W! c( e
2)使用DSN连接。通常DSN连接并不需要密码,还是需要提供一个PSW的关键字。
) U7 b* p- H1 P$ C2 ^4 i1        cnxn = pyodbc.connect('DSN=testWD=password'), ]/ M( C: W8 ]% N! M" u. Q
2        cursor = cnxn.cursor()
. X. `' Z% [4 m: U0 h( q
) p- }' i' }* Q4 C& f, m% c关于连接函数还有更多的选项,可以在pyodbc文档中的 connect funtion 和 ConnectionStrings查看更多的细节7 l* y; l  M7 w& K( b9 U/ T
; k: |# l; g0 h/ e/ u3 p) J! w
2、数据查询(SQL语句为 select ...from..where)
. h0 ^1 q" M& p& M' Q; g: e# G$ A1 N/ |: L& E% U/ w
1)所有的SQL语句都用cursor.execute函数运行。如果语句返回行,比如一个查询语句返回的行,你可以通过游标的fetch函数来获取数据,这些函数有(fetchone,fetchall,fetchmany).如果返回空行,fetchone函数将返回None,而fetchall和fetchmany将返回一个空列。
% V3 \9 c! w4 O8 o* W( W3 l1        cursor.execute("select user_id, user_name from users")- d2 ]/ n! |' I- j, `7 [
2        row = cursor.fetchone()
2 b" S  p3 L( X) ]; u4 S3        if row:
/ \, Q0 Z; c2 i6 x0 O0 D0 _/ V8 B3 s4            print row
2 M* }- j! O" A7 W% ?6 U% d* ^7 q7 A' W  R
2)Row这个类,类似于一个元组,但是他们也可以通过字段名进行访问。
. u' _% g2 j, [1        cursor.execute("select user_id, user_name from users")
! {, K0 U! h- g# q( k% ?2        row = cursor.fetchone()
( R/ _: b- t3 t- t/ r3        print 'name:', row[1]          # access by column index) P3 y# l1 \* i! b4 o8 L
4        print 'name:', row.user_name   # or access by name
3 p, v5 |6 j, A% M/ ]/ b: q
" S, w# G$ H" H/ e4 e: p3)如果所有的行都被检索完,那么fetchone将返回None.
, ^* o. n" _. S6 z! f9 G; Y. ?1        while 1:, c  c( @! Y4 b( [( `6 O
2            row = cursor.fetchone()
+ N) F, @* b# I0 J3            if not row:2 Y+ x0 G+ B* R( ]+ ^" i$ h/ H
4                break
5 P' {* j, m( }  R$ O5            print 'id:', row.user_id7 i! \$ ]0 y" S; P3 U& J

! b1 C: a( K" _3 N" J+ p' d4)使用fetchall函数时,将返回所有剩下的行,如果是空行,那么将返回一个空列。(如果有很多行,这样做的话将会占用很多内存。未读取的行将会被压缩存放在数据库引擎中,然后由数据库服务器分批发送。一次只读取你需要的行,将会大大节省内存空间)* K6 }, N: B: ?+ _5 {& i% ]
1        cursor.execute("select user_id, user_name from users")+ o8 q" q- O/ [; }
2        rows = cursor.fetchall()& O, O  v9 G- O( N' T
3        for row in rows:
/ V( M" [3 p& i4            print row.user_id, row.user_name
+ k' J, b6 A) V. h% _! W* d7 X5 j+ o2 M+ v* N
5)如果你打算一次读完所有数据,那么你可以使用cursor本身。' _$ ^8 @4 S  n2 \8 h1 ], y' O0 @
1        cursor.execute("select user_id, user_name from users"):/ k! z: o) E6 N
2        for row in cursor:
+ {$ u( y( [$ b3 ^' K6 `* d% `3            print row.user_id, row.user_name" v! W3 @+ u+ ~1 ~( u# S

7 A1 P5 ^" T* v6)由于cursor.execute返回一个cursor,所以你可以把上面的语句简化成:" N8 h' n2 Y# h0 r3 U
1        for row in cursor.execute("select user_id, user_name from users"):
# n7 |8 C& a! p; Z! v2            print row.user_id, row.user_name
  d& n$ v6 Y  W
. q( I4 Z6 X/ T+ L& c9 T7)有很多SQL语句用单行来写并不是很方便,所以你也可以使用三引号的字符串来写:; Y; y* v. D0 s6 A- f; R4 ^# {
1        cursor.execute("""
9 G) o2 ]* T) {+ {$ v2 _2                       select user_id, user_name
5 H6 F3 @1 e7 f% }; X3                         from users
) ]' O5 j% m# ~+ \# @. ?4 f+ f4                        where last_logon < '2001-01-01'
/ n+ ?1 Y. M" v& m7 D9 e& m, x5 b- d' Y5                          and bill_overdue = 'y'" ]; l. J6 X5 [8 L; t; M% I( M: f
6                       """). P: L) q2 v/ K3 i/ p
/ Q- t6 p9 a6 y( D3 W% r
3、参数# p* M# V# d; H$ W6 S, m

7 P# H& O- w# h+ @, E% M, g! v1)ODBC支持在SQL语句中使用一个问号来作为参数。你可以在SQL语句后面加上值,用来传递给SQL语句中的问号。9 R  S- `0 B# Q/ r/ D, `% I
1        cursor.execute("""
; e8 S$ Z1 r/ ]0 F& j# C2                       select user_id, user_name, O6 @& B$ F2 R0 c
3                         from users
8 s) H6 m7 {& v; h; A; v: C4                        where last_logon < ?
( z, S6 w9 ~* g5 y" F5                          and bill_overdue = ?
) e0 b4 p+ Y( h; b6                       """, '2001-01-01', 'y')6 r& k6 y4 l& P

* v, T) f, O+ G; j" C( Y5 n  X这样做比直接把值写在SQL语句中更加安全,这是因为每个参数传递给数据库都是单独进行的。如果你使用不同的参数而运行同样的SQL语句,这样做也更加效率。" G/ |  v) y) ]* N

: O4 l) l4 p$ I3)python DB API明确说明多参数时可以使用一个序列来传递。pyodbc同样支持:
, c8 L6 ]* F) u2 L' }1 I; V$ f1        cursor.execute("""' ^# R- Q, R; H" D8 Y% }4 B& n; H
2                       select user_id, user_name
) ~- Z  k0 M7 w, w4 B' W3                         from users
0 C4 O4 l8 f) \" F2 g; B1 p4                        where last_logon < ?
3 k7 G/ o- M/ b5 M. N" x5                          and bill_overdue = ?  |  o) F! a# [& j" x
6                       """, ['2001-01-01', 'y'])$ b/ {1 G' Q# i* u8 ?* g. S, E

. m$ n8 w+ a: b7 v$ v1        cursor.execute("select count(*) as user_count from users where age > ?", 21)
( P; M! X- S+ N! T2        row = cursor.fetchone()
* R( k$ P8 T( C' e: n' g3        print '%d users' % row.user_count7 \% ]" `/ D0 O' N6 {
& X9 z2 |' \: E8 w' ?
7 I0 h8 y/ G! Y9 M4 t* b  _5 `
3 U9 E( L7 ^& W) w# V" b# q
4、数据插入
- k9 {& d8 J4 ~; m" C
  F# `9 f- h1 H! ?" O$ `" r9 l1)数据插入,把SQL插入语句传递给cursor的execute函数,可以伴随任何需要的参数。- t& ~0 Z8 X$ o
1        cursor.execute("insert into products(id, name) values ('pyodbc', 'awesome library')")
* S2 x; a! g' _3 ~1 y2        cnxn.commit()5 J0 j5 ?+ B6 \7 [' h

5 u# v' C- o+ R  k% K1        cursor.execute("insert into products(id, name) values (?, ?)", 'pyodbc', 'awesome library')! F( ^( p6 r+ @8 _- e5 S* s
2        cnxn.commit()$ k6 Y1 J/ b! e. z; ?3 b# s7 L

7 d6 M& @8 M8 P6 |! |注意调用cnxn.commit()函数:你必须调用commit函数,否者你对数据库的所有操作将会失效!当断开连接时,所有悬挂的修改将会被重置。这很容易导致出错,所以你必须记得调用commit函数。/ \1 ~2 f' R7 w# e8 Z" I. f" |- O

( w: t% ~6 a% @( V; Y+ E* n5 E5 i5、数据修改和删除
. a8 X* s: V1 v+ h1 h  [
: A% I- k- m# I. @1)数据修改和删除也是跟上面的操作一样,把SQL语句传递给execute函数。但是我们常常想知道数据修改和删除时,到底影响了多少条记录,这个时候你可以使用cursor.rowcount的返回值。) x' P3 J4 p8 Q0 Q$ z0 n8 Z% K/ x
1        cursor.execute("delete from products where id <> ?", 'pyodbc')
+ d2 W- s8 o! p2        print cursor.rowcount, 'products deleted'* ]0 o" `; j3 [' ~
3        cnxn.commit()
& A) w4 _3 K/ A; E) ?8 s  p2 g7 g5 Y
2)由于execute函数总是返回cursor,所以有时候你也可以看到像这样的语句:(注意rowcount放在最后面)0 _( z/ a# D. X4 `8 A  T$ B) c
1        deleted = cursor.execute("delete from products where id <> 'pyodbc'").rowcount) B" P5 K  I8 s1 K9 K7 m8 j
2        cnxn.commit()
% w3 \* v. [& |! `1 X/ y( @* V  U& a0 V
同样要注意调用cnxn.commit()函数7 W6 }" h2 E! W3 \

8 `" r5 a5 S0 x8 r6、小窍门) r2 S" k! f  ^' ]
8 k$ C/ J' O' V# {
1)由于使用单引号的SQL语句是有效的,那么双引号也同样是有效的:
" a3 j  d+ E( j: [" J1        deleted = cursor.execute("delete from products where id <> 'pyodbc'").rowcount& e. n- i2 B! D/ p

; ?+ `$ \1 C9 _3 E6 t# }2)假如你使用的是三引号,那么你也可以这样使用:  s: v4 y7 E( k- F3 `; ?5 L
1        deleted = cursor.execute("""
, r3 A7 f2 Z9 k6 u. w, d2                                 delete
9 o4 {) l# y, V: h7 @' h3                                   from products2 i# Y7 ?4 J( S: ~8 D# q
4                                  where id <> 'pyodbc'
$ K1 J& s) @) V, g$ @( \9 m1 ^. I5                                 """).rowcount4 g* C: v$ }7 G7 R! M; Y6 F) Z7 S

, ?4 \, j4 g) S0 V4 {3)有些数据库(比如SQL Server)在计数时并没有产生列名,这种情况下,你想访问数据就必须使用下标。当然你也可以使用“as”关键字来取个列名(下面SQL语句的“as name-count”)
6 W2 ]: Z* Z3 h% |  k6 J0 V7 l  h1        row = cursor.execute("select count(*) as user_count from users").fetchone()/ {  I  {6 y. M
2        print '%s users' % row.user_count1 S0 j" F+ t9 i: Y! z
8 _" E8 E. E# u
4)假如你只是需要一个值,那么你可以在同一个行局中使用fetch函数来获取行和第一个列的所有数据。* _( e% p8 Z7 S$ _) [
1        count = cursor.execute("select count(*) from users").fetchone()[0]
0 K9 q* H% ]3 f6 W4 R2        print '%s users' % count8 `$ |; m4 G9 ~' w. O. |+ t7 E

1 P; C; U# k" Y7 K/ y如果列为空,将会导致该语句不能运行。fetchone()函数返回None,而你将会获取一个错误:NoneType不支持下标。如果有一个默认值,你能常常使用ISNULL,或者在SQL数据库直接合并NULLs来覆盖掉默认值。
& [0 j+ O5 G# r1        maxid = cursor.execute("select coalesce(max(id), 0) from users").fetchone()[0]
" `) J# \2 Y+ ~1 c" O
8 v; J# i5 M# t. ~- g( o( W在这个例子里面,如果max(id)返回NULL,coalesce(max(id),0)将导致查询的值为0。




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