- 在线时间
- 155 小时
- 最后登录
- 2013-4-28
- 注册时间
- 2012-5-7
- 听众数
- 5
- 收听数
- 0
- 能力
- 2 分
- 体力
- 2333 点
- 威望
- 0 点
- 阅读权限
- 50
- 积分
- 913
- 相册
- 1
- 日志
- 26
- 记录
- 52
- 帖子
- 291
- 主题
- 102
- 精华
- 0
- 分享
- 6
- 好友
- 84
升级   78.25% TA的每日心情 | 开心 2013-4-28 12:11 |
|---|
签到天数: 160 天 [LV.7]常住居民III
 群组: 数学软件学习 |
1、连接数据库
" s3 j/ a. ~' Y. o, i! N- @- m4 D
; W/ x8 e# z+ a, s) C* J) ^1)直接连接数据库和创建一个游标(cursor)" z! c L$ R: [4 y
1 cnxn = pyodbc.connect('DRIVER={SQL Server};SERVER=localhost;DATABASE=testdb;UID=me WD=pass')
! Q( p. f$ s- |, s# J/ A2 cursor = cnxn.cursor()1 u$ ], d9 E( `2 S
* P% `- G% z! x) O9 s$ E% [2)使用DSN连接。通常DSN连接并不需要密码,还是需要提供一个PSW的关键字。
0 n Z5 {+ F/ B/ L1 cnxn = pyodbc.connect('DSN=test WD=password')7 \; g# S1 z( W: e5 A
2 cursor = cnxn.cursor()# e7 x- v- R; u7 F. G7 v& O
! o) P! B' Z+ N6 w$ h. d0 _0 C* |( Z
关于连接函数还有更多的选项,可以在pyodbc文档中的 connect funtion 和 ConnectionStrings查看更多的细节, N% v" S0 a; x* L* x
5 c+ @' M: t; M" ^ m0 }& U( ]" j
2、数据查询(SQL语句为 select ...from..where)
# D5 G% d2 [' o8 l+ X* T+ k0 L( y2 ^# e! L$ u' K4 Y4 y
1)所有的SQL语句都用cursor.execute函数运行。如果语句返回行,比如一个查询语句返回的行,你可以通过游标的fetch函数来获取数据,这些函数有(fetchone,fetchall,fetchmany).如果返回空行,fetchone函数将返回None,而fetchall和fetchmany将返回一个空列。
- P+ I2 c. c. h3 C: U+ x1 cursor.execute("select user_id, user_name from users")
. k& X) i' t3 e) m! r" d& d) u$ o9 k2 row = cursor.fetchone()
' m. A) h3 Z; n/ D/ O3 B3 if row:
1 P _/ N' r+ E$ T' a4 print row/ V: P z- o9 d! `. D
2 t: }5 Z0 Z" H7 ]* U7 g0 X
2)Row这个类,类似于一个元组,但是他们也可以通过字段名进行访问。# @7 r& W" x4 P* e; s
1 cursor.execute("select user_id, user_name from users")
1 `7 T* P0 k' f# P2 row = cursor.fetchone()/ ]3 ~; i8 I3 B
3 print 'name:', row[1] # access by column index
- o& r* z$ x& c% ^. i) F4 print 'name:', row.user_name # or access by name7 H+ V" @ m0 M" w% T( E
2 S9 y @( Q! p R/ f: U9 h3)如果所有的行都被检索完,那么fetchone将返回None.+ @. Z4 T. _9 }- }+ E9 B
1 while 1: [! I8 u* L+ r. O
2 row = cursor.fetchone()
+ u) k' X8 x* @+ I8 a# Z3 @# q- x3 if not row:
2 c' S' g/ e M2 ]4 break% u5 i; K0 M; c
5 print 'id:', row.user_id
+ @) M3 x7 g) N6 o% a6 S* J- Q3 F( P s/ @( }' @
4)使用fetchall函数时,将返回所有剩下的行,如果是空行,那么将返回一个空列。(如果有很多行,这样做的话将会占用很多内存。未读取的行将会被压缩存放在数据库引擎中,然后由数据库服务器分批发送。一次只读取你需要的行,将会大大节省内存空间)9 j5 e3 P# n; G& L; e
1 cursor.execute("select user_id, user_name from users")
i; }! `, m% U* ?( p2 rows = cursor.fetchall()
+ f8 @+ A; j5 x. _ u3 for row in rows:
+ m4 _( f" N( K! y+ e; e4 print row.user_id, row.user_name
( u7 V+ c2 H9 ~6 Q/ o, d
: ~9 j' F$ @/ L$ z$ T5)如果你打算一次读完所有数据,那么你可以使用cursor本身。
/ t2 G$ T% I5 [- b1 O9 A1 cursor.execute("select user_id, user_name from users"):
: S$ ~) C0 V3 f# d2 for row in cursor:
1 M9 J5 o0 w- l0 y3 print row.user_id, row.user_name
0 h" `" ~; U, d* w$ ?. o+ v+ s' R! @# |- @4 r
6)由于cursor.execute返回一个cursor,所以你可以把上面的语句简化成:
- c! o. G0 {4 P# I8 p. D: b$ R1 for row in cursor.execute("select user_id, user_name from users"):- f) {3 q1 |- I3 Z& R+ W
2 print row.user_id, row.user_name# `9 g; ?: }. S; Q! s0 L
; v( C7 p2 S0 ^ X/ W7)有很多SQL语句用单行来写并不是很方便,所以你也可以使用三引号的字符串来写:
0 @/ r8 y7 n s8 E: k* T4 \- p: @1 cursor.execute(""") A, T$ L& F9 Z, Z) ?6 K4 k2 I
2 select user_id, user_name) t5 G- M& { i( n2 ^: |
3 from users
' \5 m0 a7 Y/ [2 s( P L3 b9 ]4 where last_logon < '2001-01-01'
4 T5 D# V. N8 u" J, ]# m) I6 N" R d, Z5 and bill_overdue = 'y'
# b% ]" t$ @. a5 V0 V: i6 """)
: v- W1 _' \6 g- g. _ Q; ?8 t- Q2 D# d/ m( }( e' i/ t5 I5 J
3、参数
+ L- d- `# o2 n
; ]) y* X- b7 k) x4 w# u! D, \1)ODBC支持在SQL语句中使用一个问号来作为参数。你可以在SQL语句后面加上值,用来传递给SQL语句中的问号。
' Z# ^2 [! J9 M1 cursor.execute("""" B. }0 }- H* B% }5 [3 Q' x
2 select user_id, user_name& r7 \* n; W2 s$ y4 `+ |/ G
3 from users- L8 o( R" [8 a% g7 J s
4 where last_logon < ?
1 F9 I# x, W/ u& ^0 V- A9 L8 z5 and bill_overdue = ?
- C5 a F6 V4 b D' ]6 """, '2001-01-01', 'y')
# z7 y, O' e$ Z0 U% g% C& g1 a
# r& l2 R: k5 V2 B" W& y0 D这样做比直接把值写在SQL语句中更加安全,这是因为每个参数传递给数据库都是单独进行的。如果你使用不同的参数而运行同样的SQL语句,这样做也更加效率。. m1 G, E& X3 h
/ d% C- R" _: L+ O
3)python DB API明确说明多参数时可以使用一个序列来传递。pyodbc同样支持:
2 o) H4 ]3 w% M5 u e1 cursor.execute("""; j R6 s" P& u" U
2 select user_id, user_name, [* E+ k9 g( W; k; [' `
3 from users# x- \5 N. h, |& y( N$ M( q
4 where last_logon < ?
* o, M0 ^5 T7 X- v' g. H9 `- g5 and bill_overdue = ?' l* s# Z9 }; S5 G8 @, ]
6 """, ['2001-01-01', 'y']), e! `# f3 t! f, J/ L
, F7 N- j5 o: D e( \1 cursor.execute("select count(*) as user_count from users where age > ?", 21)# P1 z# n6 |6 [7 E
2 row = cursor.fetchone()! a" B9 H+ u9 h4 a# {: T; ~
3 print '%d users' % row.user_count
: {, E5 t/ N+ v% t+ D0 e1 I; @8 S6 J3 |9 @- D* [; o
( w2 e( t; K1 @6 T. T/ t
/ L& W- U) B* g9 h4、数据插入
) {. e* E3 |3 P+ N; u
) \& U& Z1 m8 E! \* T7 \1)数据插入,把SQL插入语句传递给cursor的execute函数,可以伴随任何需要的参数。- k8 H! u j8 Y( s; o# X3 N
1 cursor.execute("insert into products(id, name) values ('pyodbc', 'awesome library')")
' N* x. g( C$ Q2 cnxn.commit()# G( V5 Y7 i7 ~& _, Q: H( X
7 q/ _+ l2 L; w' l4 e1 cursor.execute("insert into products(id, name) values (?, ?)", 'pyodbc', 'awesome library')" k* p3 [& v4 A( r1 Q
2 cnxn.commit()+ l! Z& p$ Y1 r, H0 r
1 K3 D; D6 J# p: k注意调用cnxn.commit()函数:你必须调用commit函数,否者你对数据库的所有操作将会失效!当断开连接时,所有悬挂的修改将会被重置。这很容易导致出错,所以你必须记得调用commit函数。: q* {% F8 R" }* P# L j2 ~
2 A7 I7 b' l5 Z4 C3 k7 ]; h7 c
5、数据修改和删除% x- L* e z8 c8 I9 H
9 |1 q t# C2 j) ^
1)数据修改和删除也是跟上面的操作一样,把SQL语句传递给execute函数。但是我们常常想知道数据修改和删除时,到底影响了多少条记录,这个时候你可以使用cursor.rowcount的返回值。
3 Z( T2 X3 B O" e: Z1 cursor.execute("delete from products where id <> ?", 'pyodbc')1 }+ w1 j4 u' [: W) A
2 print cursor.rowcount, 'products deleted'
B6 V6 @+ b" u9 k% I3 cnxn.commit()3 {( K. `) G& M. ?2 k
! v, Z5 P9 Z; O: ]8 E% z8 {
2)由于execute函数总是返回cursor,所以有时候你也可以看到像这样的语句:(注意rowcount放在最后面)
: d% ^) y; R- D/ k1 deleted = cursor.execute("delete from products where id <> 'pyodbc'").rowcount
9 x4 l K( M1 G0 N; @. I4 d2 cnxn.commit()! b( ^' c/ E# V' T) _
9 J3 J0 R: F: D8 j ~+ b' q同样要注意调用cnxn.commit()函数
1 D$ u1 @3 y4 }
' ?+ |6 T5 G* N! }6、小窍门
' `7 T, ]& U: o% u9 w: Q5 M7 K; ?! |+ n" p j8 w: \
1)由于使用单引号的SQL语句是有效的,那么双引号也同样是有效的:) u f2 i7 H# a; m
1 deleted = cursor.execute("delete from products where id <> 'pyodbc'").rowcount0 y# U5 \1 F: h7 t* a+ j1 V; D7 U, ~# f4 X
& ?0 L I! b" e" n: N1 w' a `
2)假如你使用的是三引号,那么你也可以这样使用:$ o- m/ l8 |6 I/ O
1 deleted = cursor.execute("""
9 p+ a/ _0 j7 c. M7 i! n$ @, l2 delete
! \7 K) A) y7 @3 from products
( z0 @! J e8 w0 j& `6 j; Z7 ~4 where id <> 'pyodbc'
7 r8 n2 p' i6 Y# Q: X g5 """).rowcount
) I: ?) o/ Y+ x- I/ P% C; r# ]" T$ E/ C$ x% ~% X. A' P
3)有些数据库(比如SQL Server)在计数时并没有产生列名,这种情况下,你想访问数据就必须使用下标。当然你也可以使用“as”关键字来取个列名(下面SQL语句的“as name-count”)6 @; t# w$ ?! r
1 row = cursor.execute("select count(*) as user_count from users").fetchone()
# X! k v9 k% L$ Q2 print '%s users' % row.user_count+ Y7 z& a, \% O- d' N7 p
: s: u p' l/ `2 @4)假如你只是需要一个值,那么你可以在同一个行局中使用fetch函数来获取行和第一个列的所有数据。
: x0 A- R2 H3 j, E$ S2 ^1 count = cursor.execute("select count(*) from users").fetchone()[0]( R( H& b9 p+ q
2 print '%s users' % count
# {/ ]7 ~7 I' s; a8 Z4 P+ _
7 I6 D/ |" f+ Y如果列为空,将会导致该语句不能运行。fetchone()函数返回None,而你将会获取一个错误:NoneType不支持下标。如果有一个默认值,你能常常使用ISNULL,或者在SQL数据库直接合并NULLs来覆盖掉默认值。
# Y; B. \* K7 r$ W) j! I# Q1 maxid = cursor.execute("select coalesce(max(id), 0) from users").fetchone()[0]2 n# F0 y5 {; g! K5 N7 V+ ^9 Y8 l
. _6 W N+ j- a& v' g @在这个例子里面,如果max(id)返回NULL,coalesce(max(id),0)将导致查询的值为0。 |
zan
|