1、连接数据库 8 f& ~$ M; v; l9 E7 I# d8 V; N1 z2 x
1)直接连接数据库和创建一个游标(cursor)) y6 y7 Z( c5 h7 F7 B9 ]
1 cnxn = pyodbc.connect('DRIVER={SQL Server};SERVER=localhost;DATABASE=testdb;UID=meWD=pass')$ z' P# t( m/ p5 I2 b9 C
2 cursor = cnxn.cursor() % ~& Z, R7 D* i. K" u% D% | ( v6 `* l* g: c$ A3 T2 D8 T) T2)使用DSN连接。通常DSN连接并不需要密码,还是需要提供一个PSW的关键字。 % {8 ~0 ]% r% X) |1 cnxn = pyodbc.connect('DSN=testWD=password') L5 J' w& l' h
2 cursor = cnxn.cursor() , H, ?# D, y. l9 w; f. j1 y# n
关于连接函数还有更多的选项,可以在pyodbc文档中的 connect funtion 和 ConnectionStrings查看更多的细节7 @) ]6 C; _. O, l3 F
8 q2 I% }' `# K- H; }, F8 u0 c2、数据查询(SQL语句为 select ...from..where) / @! `: X7 Z; d/ j* l, P; q8 [7 s6 K" x6 U5 V7 k: F
1)所有的SQL语句都用cursor.execute函数运行。如果语句返回行,比如一个查询语句返回的行,你可以通过游标的fetch函数来获取数据,这些函数有(fetchone,fetchall,fetchmany).如果返回空行,fetchone函数将返回None,而fetchall和fetchmany将返回一个空列。 # h# z; G% @5 ?# g7 ]+ b" b- v1 cursor.execute("select user_id, user_name from users")' h; {% }0 W' r3 R
2 row = cursor.fetchone() d; F; l& F% \3 if row:7 b7 M2 u4 i6 X) L
4 print row 2 y2 x, E$ x+ ]+ Z$ {6 a* @% g$ R8 B' b" _ E
2)Row这个类,类似于一个元组,但是他们也可以通过字段名进行访问。 ' d7 k7 R% x7 g9 C0 n& J1 cursor.execute("select user_id, user_name from users")& M8 M& I3 R6 O( R
2 row = cursor.fetchone() . G) t3 i- V3 i! Z3 print 'name:', row[1] # access by column index @8 ]2 @& {6 z$ M: C" E% e: p
4 print 'name:', row.user_name # or access by name" ~6 R# e' x" l
0 m; h$ B3 _% W. m
3)如果所有的行都被检索完,那么fetchone将返回None.- i! }3 o3 Y5 \8 Q8 ~. \' ]5 e
1 while 1: 1 r7 I+ O0 T! h2 row = cursor.fetchone()5 t( C; C% _) @# Z6 m! @
3 if not row:% w7 e8 c3 x' H) K5 g# Z
4 break. _% C. A$ i% t" \/ { \ R
5 print 'id:', row.user_id 6 f: t4 o u& i* S/ d Z/ q0 [2 g1 c$ x& [
4)使用fetchall函数时,将返回所有剩下的行,如果是空行,那么将返回一个空列。(如果有很多行,这样做的话将会占用很多内存。未读取的行将会被压缩存放在数据库引擎中,然后由数据库服务器分批发送。一次只读取你需要的行,将会大大节省内存空间) 9 L2 q- u; J4 ?4 p v: |, B; H( ^1 cursor.execute("select user_id, user_name from users") , @9 ~$ T r- c/ M' V' S, j# `2 rows = cursor.fetchall() ! m% Z2 P, z" G3 for row in rows:9 D3 k; v6 o9 |
4 print row.user_id, row.user_name 9 ?, Q" H$ p) m* Z, J) W0 A" k7 f O# s7 R6 Z& w7 Y* b
5)如果你打算一次读完所有数据,那么你可以使用cursor本身。. l, \1 R3 H3 V( c& z
1 cursor.execute("select user_id, user_name from users"): ! m- v0 \( s% \; t% I2 for row in cursor:; H! P! ]/ s9 N! M3 A- W
3 print row.user_id, row.user_name 7 ]8 x9 s4 Z5 l# Q9 }1 X0 W! u0 A, y! m+ N, c. ?+ \
6)由于cursor.execute返回一个cursor,所以你可以把上面的语句简化成:# _+ U% k* E4 p: [6 `# b, {
1 for row in cursor.execute("select user_id, user_name from users"):) F1 \" t7 b: m3 [9 g; F
2 print row.user_id, row.user_name$ b) r8 j2 r+ _/ u8 A
7 t9 A2 d8 v) }0 z6 V7)有很多SQL语句用单行来写并不是很方便,所以你也可以使用三引号的字符串来写: 6 b0 K) Y) ^. T9 h4 A5 h9 G8 }. ?1 cursor.execute("""9 o6 W0 x: C$ X+ H7 v
2 select user_id, user_name% ]6 V) c; h0 e2 D! I+ y0 E: R
3 from users f- ?0 N$ d4 \, m) m0 L. V
4 where last_logon < '2001-01-01'0 V$ @- ~* ^+ N9 b5 n
5 and bill_overdue = 'y'5 T r9 |) I* f' E# H
6 """); I) u/ T' V" Z' b( [2 s, s
- O3 T5 N% U3 w: a% w }
3、参数 : @/ p' p# N3 y& W: } " {0 o4 t) r+ _* w8 p: U1)ODBC支持在SQL语句中使用一个问号来作为参数。你可以在SQL语句后面加上值,用来传递给SQL语句中的问号。 ) r- N; @& u2 v- R$ ?- w1 cursor.execute("""8 t5 T: n! J& R8 W4 ]! J
2 select user_id, user_name# j3 K3 f4 r* q0 v, Z
3 from users4 _& Y+ |/ V' c' U" {' x% X
4 where last_logon < ?+ W2 z( I- X1 M! `. i
5 and bill_overdue = ?! b- ~' K9 k7 B9 V' Q6 n1 K
6 """, '2001-01-01', 'y'), T1 ^3 u9 y1 W8 [+ u0 T* U$ _& W# m
4 s; m u/ g {1 \) e( ?% p) N
这样做比直接把值写在SQL语句中更加安全,这是因为每个参数传递给数据库都是单独进行的。如果你使用不同的参数而运行同样的SQL语句,这样做也更加效率。 " R- S3 Z8 _0 ?6 D # N2 G/ ?& w2 r+ b3)python DB API明确说明多参数时可以使用一个序列来传递。pyodbc同样支持:0 u# R$ o% @8 G9 `5 f( ]4 K
1 cursor.execute(""" ; O# Y1 r* p& C& I' w2 select user_id, user_name( `" d" U9 u4 u/ r' E" r
3 from users9 f, s6 V7 P9 o% r$ z1 |$ R5 c
4 where last_logon < ?% g% y' D% n6 d
5 and bill_overdue = ? : Z: t; q1 @1 e& P2 [0 n4 O6 B6 """, ['2001-01-01', 'y']) $ y# C8 R% a8 k0 d 5 Q9 ~+ e% g. `1 cursor.execute("select count(*) as user_count from users where age > ?", 21) : V( J& S1 p# Q' F, i, s4 {2 row = cursor.fetchone()4 C7 X) s# x7 ]/ m
3 print '%d users' % row.user_count 3 Q+ G& t/ w; m- h: Z: ?( T" s( p( p5 J [# n- K$ E
. u$ O# e- ~0 i % d& P0 G+ V- B' r3 \4、数据插入 7 c" M i; x2 }- j " M2 K( I# B* l1)数据插入,把SQL插入语句传递给cursor的execute函数,可以伴随任何需要的参数。 . u: E- U, @2 ^: a/ W6 F, t1 cursor.execute("insert into products(id, name) values ('pyodbc', 'awesome library')") 3 n5 A% X2 s, k2 cnxn.commit()% g9 x @* b: `# G4 O% N3 \ U# c# X
7 m; K* d2 X9 n* m$ c, W- K, S1 cursor.execute("insert into products(id, name) values (?, ?)", 'pyodbc', 'awesome library') % m4 q+ Y& C5 N6 f2 cnxn.commit() + R/ ^& K3 p4 _ O, z: B9 t L
注意调用cnxn.commit()函数:你必须调用commit函数,否者你对数据库的所有操作将会失效!当断开连接时,所有悬挂的修改将会被重置。这很容易导致出错,所以你必须记得调用commit函数。3 t @1 ^8 s2 f. {9 G
. Y' K% f- \- z0 E$ f7 z5、数据修改和删除 ; C9 m! Y; a C, _ 5 X5 z9 E# a( n) ?# z4 ?1)数据修改和删除也是跟上面的操作一样,把SQL语句传递给execute函数。但是我们常常想知道数据修改和删除时,到底影响了多少条记录,这个时候你可以使用cursor.rowcount的返回值。' W% d9 r2 p$ O* v3 n
1 cursor.execute("delete from products where id <> ?", 'pyodbc')& s6 `8 x0 S% h" s
2 print cursor.rowcount, 'products deleted' # `( q$ K% y5 Z( X/ p4 C/ t3 cnxn.commit()+ w) \+ i1 h0 c' T2 K
0 }3 ?7 K, a$ Q6 X5 c# Z6 T
2)由于execute函数总是返回cursor,所以有时候你也可以看到像这样的语句:(注意rowcount放在最后面)% d) G: Q k0 v# V2 _. E
1 deleted = cursor.execute("delete from products where id <> 'pyodbc'").rowcount b' {2 `5 e4 v+ E
2 cnxn.commit()3 h. S( H) U) I( P4 m* p
! _) E; D' @# t7 \/ y/ G5 M同样要注意调用cnxn.commit()函数- e! N6 X9 p' U+ a- ~( {
4 A; Y* T( A+ E H* ~6、小窍门# { n3 L2 A/ A9 C1 W
3 y: w% A6 |, q1)由于使用单引号的SQL语句是有效的,那么双引号也同样是有效的:8 e& K' B: L4 O2 [- d
1 deleted = cursor.execute("delete from products where id <> 'pyodbc'").rowcount! D& F. a$ Z. ~: ]) d
9 }" W3 S' z' r6 G4 Q9 K
2)假如你使用的是三引号,那么你也可以这样使用: $ k. t" S( B. u( m G5 f1 deleted = cursor.execute("""1 M' I9 q( M) g/ b' N. o
2 delete( n1 b# g; [+ a' s# z! z d
3 from products 0 _# u1 B0 N/ V/ C4 where id <> 'pyodbc'% Y/ j2 f9 h9 H- {& K. @# m
5 """).rowcount; T2 [4 ^0 _- T3 E5 O
$ i, D, |5 t" {2 D
3)有些数据库(比如SQL Server)在计数时并没有产生列名,这种情况下,你想访问数据就必须使用下标。当然你也可以使用“as”关键字来取个列名(下面SQL语句的“as name-count”) - Y$ X/ h& `; S5 i1 row = cursor.execute("select count(*) as user_count from users").fetchone()! F. z, y& e& N, d' H9 k
2 print '%s users' % row.user_count , S* }5 @) h9 @7 \& m4 p' f6 Y [ C4 m& ?1 ?" ^; u- G& A
4)假如你只是需要一个值,那么你可以在同一个行局中使用fetch函数来获取行和第一个列的所有数据。 1 ?' I! q" ^' C6 ^) s& _! f1 count = cursor.execute("select count(*) from users").fetchone()[0] 9 H! b1 } A* e6 d: Q2 print '%s users' % count# N5 R# `: H0 H; x$ N& @, {
: c. A5 C0 U( Q% H如果列为空,将会导致该语句不能运行。fetchone()函数返回None,而你将会获取一个错误:NoneType不支持下标。如果有一个默认值,你能常常使用ISNULL,或者在SQL数据库直接合并NULLs来覆盖掉默认值。; i+ J+ A8 L a9 q) k
1 maxid = cursor.execute("select coalesce(max(id), 0) from users").fetchone()[0] * L) S( A/ L2 ^# B0 c. Y. T* ^ i$ z$ Y9 K
在这个例子里面,如果max(id)返回NULL,coalesce(max(id),0)将导致查询的值为0。