- 在线时间
- 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、连接数据库
& r: U2 t" E$ Q! H ?) F6 X4 z% Z, h& x' |/ ~! {2 ~
1)直接连接数据库和创建一个游标(cursor). |' z0 [8 U6 {$ H- u e9 K* W, T
1 cnxn = pyodbc.connect('DRIVER={SQL Server};SERVER=localhost;DATABASE=testdb;UID=me WD=pass')! t- {5 F5 p. W+ m( |
2 cursor = cnxn.cursor()
7 i( w* U4 i/ y( K: d9 Z: I; E* J! g) U0 L
2)使用DSN连接。通常DSN连接并不需要密码,还是需要提供一个PSW的关键字。; M- }# W. u! t+ D+ |
1 cnxn = pyodbc.connect('DSN=test WD=password')/ [* `# @! V z) |
2 cursor = cnxn.cursor()
( X' |6 Y9 G( P, r9 p" P
# ^2 S- }3 v, T0 L关于连接函数还有更多的选项,可以在pyodbc文档中的 connect funtion 和 ConnectionStrings查看更多的细节6 e9 f! e* u0 ~0 ^
% C2 @/ G# V( A/ g8 E2、数据查询(SQL语句为 select ...from..where). _$ M& w! G5 K7 {# t# K: n
: U9 E+ g, x8 K6 ^; m
1)所有的SQL语句都用cursor.execute函数运行。如果语句返回行,比如一个查询语句返回的行,你可以通过游标的fetch函数来获取数据,这些函数有(fetchone,fetchall,fetchmany).如果返回空行,fetchone函数将返回None,而fetchall和fetchmany将返回一个空列。6 u3 F/ U3 J9 }! H2 Y* R
1 cursor.execute("select user_id, user_name from users")
$ K: V# Y% O, Q" E: R& Y2 row = cursor.fetchone()
2 c# ~* r4 v3 j$ J4 X6 Q i, [. v6 n3 if row:
! i' F; n& z0 {- t9 ?% `4 print row
- t4 U( u" ^# J4 n& n# _
2 o1 z2 Z% j! ?& Q2)Row这个类,类似于一个元组,但是他们也可以通过字段名进行访问。5 e- M% r1 ?: E; R# y8 a
1 cursor.execute("select user_id, user_name from users")
2 }% f6 L' u+ ?& Q1 g2 row = cursor.fetchone()4 e$ W6 t& Q' ^* ?% @# [
3 print 'name:', row[1] # access by column index0 C: w6 A' F4 e( i& j
4 print 'name:', row.user_name # or access by name
- q$ B! z5 N& C/ E) A" w
' V1 h6 w0 F7 U3)如果所有的行都被检索完,那么fetchone将返回None.
3 E: t, j+ X6 u" I0 k) h1 while 1:& \3 w8 @$ U4 B( c5 W( X
2 row = cursor.fetchone()
& G# Q. W- }, A0 m k+ O3 if not row:; z0 @5 ~/ v& D& T
4 break
& {4 B3 n4 S6 f9 A5 print 'id:', row.user_id
8 |$ K1 M# i" |; v: Y8 ?6 |
3 C. L4 b& |/ Z# ]4)使用fetchall函数时,将返回所有剩下的行,如果是空行,那么将返回一个空列。(如果有很多行,这样做的话将会占用很多内存。未读取的行将会被压缩存放在数据库引擎中,然后由数据库服务器分批发送。一次只读取你需要的行,将会大大节省内存空间)
& Y& y: |/ ~9 K1 cursor.execute("select user_id, user_name from users")
0 a5 @' ?$ g. \8 \& e# i2 rows = cursor.fetchall()
' S$ f j. E% x( |! u3 for row in rows:
# f9 c- h0 V) ~: [8 p4 print row.user_id, row.user_name+ w- r: }. w8 t$ B7 N7 {
1 g. ?6 W: h; @9 y5)如果你打算一次读完所有数据,那么你可以使用cursor本身。/ t. S9 b% C# b4 `( P: N
1 cursor.execute("select user_id, user_name from users"):6 X( K0 B5 W+ f6 X/ C0 x( \
2 for row in cursor:; u% F. Q# _3 _8 B
3 print row.user_id, row.user_name
' j: r6 t7 P8 J6 Y/ d% U2 i* _: y" t" | D3 n ^& O L* `3 U
6)由于cursor.execute返回一个cursor,所以你可以把上面的语句简化成:& k4 l+ k& N) d6 ]
1 for row in cursor.execute("select user_id, user_name from users"):
: ?; I+ {& X; E' ^) x8 D, P p( {2 print row.user_id, row.user_name
G* O- }6 g- p0 D* K# `8 r& u0 j& h! O; d
7)有很多SQL语句用单行来写并不是很方便,所以你也可以使用三引号的字符串来写:+ z) ~! {/ ` o
1 cursor.execute("""1 p9 p& c, B; G* _
2 select user_id, user_name
0 O" L; [# ^. Q. ^3 Q- q3 from users" ?5 l h8 I1 i+ t4 t% V2 V
4 where last_logon < '2001-01-01'& `6 I: x0 H( z t# Y2 H; v- i
5 and bill_overdue = 'y': E- g7 ~- l: |" U8 J: m6 R
6 """)' r& B- x. Z$ m# ~& X" j
2 [; @4 ~- [6 K& G
3、参数
* K! J0 X, u( i, {$ t" k9 V6 {5 \/ Y+ u1 e% N
1)ODBC支持在SQL语句中使用一个问号来作为参数。你可以在SQL语句后面加上值,用来传递给SQL语句中的问号。- ?' I% W' ~" o! f' R! G7 K9 n
1 cursor.execute("""; }0 b" t% V1 V: e' Y$ F% C
2 select user_id, user_name6 q5 W1 i: c4 C
3 from users1 x }3 O; u7 @# ~2 i
4 where last_logon < ?
* m" j; ~0 X1 j2 v) s5 and bill_overdue = ?4 H* U) W9 [4 F
6 """, '2001-01-01', 'y'), ]: I5 f: e9 p3 E- s
* R9 t2 @, k1 F: F4 S) M2 f& F这样做比直接把值写在SQL语句中更加安全,这是因为每个参数传递给数据库都是单独进行的。如果你使用不同的参数而运行同样的SQL语句,这样做也更加效率。
7 g5 s" m7 L8 z: ], t% k' w3 Z
8 V) x( H3 Y4 i5 P: u1 D" L @3)python DB API明确说明多参数时可以使用一个序列来传递。pyodbc同样支持:( Q1 I8 \, i; _0 F
1 cursor.execute("""
+ k+ N. m# |$ H( c6 t) Y2 select user_id, user_name3 F% Y, }* a7 f6 K2 |& j
3 from users
7 s: w" H" ?' [$ P8 u2 e4 where last_logon < ?
0 `! x8 V+ _5 V- Y" {5 and bill_overdue = ?1 S" e* D. z" O/ [; V# W
6 """, ['2001-01-01', 'y'])
& f4 C/ c o" j7 l1 x
0 F& e: Q+ \4 O1 cursor.execute("select count(*) as user_count from users where age > ?", 21)
! X o9 u0 u4 H" T2 row = cursor.fetchone()
; ]9 M2 E2 W0 F3 ^: O3 print '%d users' % row.user_count) o5 P( F( b$ K, g
4 R9 f9 E; u; T9 Z/ [/ H4 B
0 }4 _& C7 @ }4 z
% g$ d( V `' _% U
4、数据插入 e; R& I% y5 H6 L0 U; @
$ k' b$ R& H+ k1 b+ F1)数据插入,把SQL插入语句传递给cursor的execute函数,可以伴随任何需要的参数。4 T' ?/ k0 B, b* Z
1 cursor.execute("insert into products(id, name) values ('pyodbc', 'awesome library')")
( |+ ^( E$ q# M) P8 C2 cnxn.commit(): l8 F( E' Q# ^, W1 q w+ D
+ c! `+ L0 `& V+ p. U, U( f+ m
1 cursor.execute("insert into products(id, name) values (?, ?)", 'pyodbc', 'awesome library')
" u+ B7 U% x# D" c8 A2 R& L9 R2 cnxn.commit()& ^& C. i8 Y9 Y: ?: u3 @9 h1 C
* b' Q4 w8 T, I9 s2 T: ~/ ~
注意调用cnxn.commit()函数:你必须调用commit函数,否者你对数据库的所有操作将会失效!当断开连接时,所有悬挂的修改将会被重置。这很容易导致出错,所以你必须记得调用commit函数。4 \- {) P+ _, u% B3 U% j
) j& \) {# n: o$ R6 c: @' H
5、数据修改和删除3 e5 O5 C- h" I8 t* k4 k
* e) ~# m8 u B& H
1)数据修改和删除也是跟上面的操作一样,把SQL语句传递给execute函数。但是我们常常想知道数据修改和删除时,到底影响了多少条记录,这个时候你可以使用cursor.rowcount的返回值。
% y" X6 G) m+ a% Z6 S; _1 cursor.execute("delete from products where id <> ?", 'pyodbc') @/ E5 [5 c% t: j
2 print cursor.rowcount, 'products deleted'
) \$ d4 E1 a, ^+ Z6 N3 cnxn.commit()
* z3 u( j+ L' o" `' v8 w( Z7 F9 v, m8 @( V$ E
2)由于execute函数总是返回cursor,所以有时候你也可以看到像这样的语句:(注意rowcount放在最后面)1 a: X2 m6 }7 l, e, L( ]1 e q
1 deleted = cursor.execute("delete from products where id <> 'pyodbc'").rowcount
- E f1 N2 ~8 j% L6 p+ a; z j0 P2 cnxn.commit()
1 h4 c# X$ S4 @; @( t' v
6 A/ r* C, b5 g7 e同样要注意调用cnxn.commit()函数
2 e0 Z* |# i2 t3 q; r0 s$ [
% Q4 ~5 Z- x y- r& |, k" P* j6、小窍门
% y ?1 ~4 i' y5 Y8 B1 s' M0 B! ~
5 u& e# Q5 M9 _: O5 k) G1)由于使用单引号的SQL语句是有效的,那么双引号也同样是有效的:2 w9 ?/ s5 D2 e5 M8 y3 \
1 deleted = cursor.execute("delete from products where id <> 'pyodbc'").rowcount
6 y- Q: @3 q5 k& B2 b" C6 E6 G$ a/ n+ @5 h
2)假如你使用的是三引号,那么你也可以这样使用:
l' d+ D* o- K2 H j1 deleted = cursor.execute("""( O0 D% l. X6 X/ L
2 delete3 S0 p( K0 M1 B
3 from products
3 e7 F; p' N, x5 h2 x4 where id <> 'pyodbc'$ z; f1 R* R1 b5 q1 k {% j% D
5 """).rowcount; q6 J( [/ Y) x
, r" X1 `9 j3 A2 z3 i6 B& \; I" Q
3)有些数据库(比如SQL Server)在计数时并没有产生列名,这种情况下,你想访问数据就必须使用下标。当然你也可以使用“as”关键字来取个列名(下面SQL语句的“as name-count”)
6 y2 u/ f, o& @$ L$ b0 w) D1 row = cursor.execute("select count(*) as user_count from users").fetchone()
# v a: m3 ~, y7 o2 print '%s users' % row.user_count- d# d$ A4 H3 ~4 l7 m5 o
9 ?: G# G, S, X+ S0 K4 ]
4)假如你只是需要一个值,那么你可以在同一个行局中使用fetch函数来获取行和第一个列的所有数据。
, x. @( M" B% z0 ]; Z% @6 x1 count = cursor.execute("select count(*) from users").fetchone()[0]
, j9 q) }3 S, e# l+ f+ Q" ^2 print '%s users' % count( _, P" ]; b4 ?! S
1 h/ z. L' P) W* l t
如果列为空,将会导致该语句不能运行。fetchone()函数返回None,而你将会获取一个错误:NoneType不支持下标。如果有一个默认值,你能常常使用ISNULL,或者在SQL数据库直接合并NULLs来覆盖掉默认值。
6 W# x5 K0 [' p; }) r5 c1 maxid = cursor.execute("select coalesce(max(id), 0) from users").fetchone()[0]8 X' r8 D @" \/ {. X
; w& f t, x4 V; q在这个例子里面,如果max(id)返回NULL,coalesce(max(id),0)将导致查询的值为0。 |
zan
|