- 在线时间
- 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、连接数据库
5 u1 F" i2 b, c% C% k P; {- N+ M" ], f: P
1)直接连接数据库和创建一个游标(cursor)
7 O# K/ [ _4 T6 b% M5 j5 [1 cnxn = pyodbc.connect('DRIVER={SQL Server};SERVER=localhost;DATABASE=testdb;UID=me WD=pass')
1 X! i' O5 ?: n! X4 e/ x' c2 cursor = cnxn.cursor()0 T+ {0 |5 O5 V3 k
# F% q+ s; Y4 g+ T$ P9 f
2)使用DSN连接。通常DSN连接并不需要密码,还是需要提供一个PSW的关键字。# c p- D6 v% _" P
1 cnxn = pyodbc.connect('DSN=test WD=password'); h1 }# q( J9 _/ |* h. c
2 cursor = cnxn.cursor()9 F6 s: w, `; t7 _& O) e
6 n3 u- v; I) ^9 Q5 s- y/ G2 A关于连接函数还有更多的选项,可以在pyodbc文档中的 connect funtion 和 ConnectionStrings查看更多的细节
- P7 i! o6 B9 G% ]% @# R* b# m' i) D7 R P' ^' V
2、数据查询(SQL语句为 select ...from..where)0 d9 i T1 q. e! l R0 u4 I
- j* o# Y K# H4 G/ E( v7 |: m
1)所有的SQL语句都用cursor.execute函数运行。如果语句返回行,比如一个查询语句返回的行,你可以通过游标的fetch函数来获取数据,这些函数有(fetchone,fetchall,fetchmany).如果返回空行,fetchone函数将返回None,而fetchall和fetchmany将返回一个空列。
n/ Q; h% j* ^- |' _1 cursor.execute("select user_id, user_name from users")" \4 B9 P# A) A0 r* h
2 row = cursor.fetchone()
/ L2 A h# S9 R b3 if row:
" `/ t. h- L& M$ Y7 \) F4 print row
5 @2 o3 q: k: M+ h% y$ l2 ^" {# f1 S" ?, I- J( b1 L) H
2)Row这个类,类似于一个元组,但是他们也可以通过字段名进行访问。1 I, o1 B* U6 Z2 ~$ B# c
1 cursor.execute("select user_id, user_name from users")
7 i8 D. A8 {* \2 row = cursor.fetchone()/ a% l* y2 j' A7 p4 A
3 print 'name:', row[1] # access by column index% G! T7 P: b! W4 T
4 print 'name:', row.user_name # or access by name- g* A1 R8 W+ d$ I+ i8 h& q
) ~% |1 T. n" m4 X @& ^# S
3)如果所有的行都被检索完,那么fetchone将返回None.
% e1 i% k) r% f1 while 1:
1 h! D! t; L6 j) _2 row = cursor.fetchone()3 }& A+ t# ^0 t
3 if not row:# [9 t$ b' u' j* A) ]: I
4 break
" C8 E3 L F. _8 u$ L2 Y5 print 'id:', row.user_id
$ R" o( ~. r( C# B* A/ X
' O0 d5 Y! f; g3 z. u) |4)使用fetchall函数时,将返回所有剩下的行,如果是空行,那么将返回一个空列。(如果有很多行,这样做的话将会占用很多内存。未读取的行将会被压缩存放在数据库引擎中,然后由数据库服务器分批发送。一次只读取你需要的行,将会大大节省内存空间)
0 `5 b2 ?0 C) X+ F+ C0 \0 }0 Y1 cursor.execute("select user_id, user_name from users")/ W$ S0 y; I' D8 p. D
2 rows = cursor.fetchall()
' U+ j- \, h2 f" b- ^3 for row in rows:
5 D3 Y( D, c' z% {3 N; i4 print row.user_id, row.user_name4 [, A6 A- E2 d6 y+ J9 |* f
t% u d) h9 ` u7 \1 l5)如果你打算一次读完所有数据,那么你可以使用cursor本身。* R. r+ B$ d$ c4 h) n( x
1 cursor.execute("select user_id, user_name from users"):9 q0 d. \% ^8 L( T- |4 H2 D
2 for row in cursor:. S P4 u% }; D% h. Y0 w1 r
3 print row.user_id, row.user_name! j* j h. l6 G/ ]
8 J3 T6 R2 v( [5 m0 l
6)由于cursor.execute返回一个cursor,所以你可以把上面的语句简化成:
( g/ n5 I- s1 l/ Q" [ {1 for row in cursor.execute("select user_id, user_name from users"):
9 q Y$ l$ p" f& j" @2 print row.user_id, row.user_name9 t% l0 S, K: D4 h1 j: w
, u( l+ x5 w0 b- M8 d( p+ v# p+ _
7)有很多SQL语句用单行来写并不是很方便,所以你也可以使用三引号的字符串来写:! o% y- E7 y) e* N1 w3 V
1 cursor.execute("""- S4 w* m& R5 `" ~' d! a, K2 t
2 select user_id, user_name8 k9 m- P5 R# |/ Q$ @
3 from users
/ u8 h1 x5 I' Z( j5 B4 where last_logon < '2001-01-01'
. P" T1 d; F% y& p8 c7 J5 and bill_overdue = 'y' K& P+ j W) Q+ q$ `) T
6 """)0 T3 N# }. C5 v; R
& L" w) ?, X$ z
3、参数
+ F8 l) b- B! H# g1 `1 L8 n0 ?! F( s8 y
1)ODBC支持在SQL语句中使用一个问号来作为参数。你可以在SQL语句后面加上值,用来传递给SQL语句中的问号。
7 b8 Y/ g) K3 j' k2 y1 cursor.execute("""
9 `1 u+ s; b+ U' @+ v( J9 d2 select user_id, user_name
) s8 k4 }" @$ z" F0 Z3 from users
Y* m; ]; `4 ^$ K( Z( x( M( E4 where last_logon < ?
, v- N7 b" H" `7 X5 and bill_overdue = ? X, e; E+ N) F
6 """, '2001-01-01', 'y'). F* [; Q( g8 g) b2 c# z
u/ U! e0 a: H. b) L& V这样做比直接把值写在SQL语句中更加安全,这是因为每个参数传递给数据库都是单独进行的。如果你使用不同的参数而运行同样的SQL语句,这样做也更加效率。
4 l- }2 ]/ F+ A+ z# D3 N% H
. J9 ~6 j9 \3 @3)python DB API明确说明多参数时可以使用一个序列来传递。pyodbc同样支持:
& {( ]8 @5 r2 G, u1 cursor.execute("""1 b, ~& J. ~% g5 i% `8 m7 u3 A( T
2 select user_id, user_name
4 L/ S |( W/ M3 from users
9 a* j' v3 Q1 v4 where last_logon < ?
7 r# i& `+ ^- a, P5 and bill_overdue = ?: Y: R8 F4 j) h2 T
6 """, ['2001-01-01', 'y'])
9 l1 w j/ W( E1 J3 h7 ]5 y1 a: q3 l6 v) w; @# y7 v* L, x
1 cursor.execute("select count(*) as user_count from users where age > ?", 21)- L$ F+ |6 y& }
2 row = cursor.fetchone()
1 p- O' c4 {9 O) j$ c z8 d' ?! O3 print '%d users' % row.user_count0 J( d* N9 e! C& X$ u8 p3 e* Q7 ^
9 ^/ I3 I0 q6 @8 V" }$ i# t : Z- X3 G a3 r5 L9 p Y/ Z
0 \1 I1 q+ G8 ^. K" Z7 r4、数据插入
0 @) D5 r0 g8 Q4 m- M
/ e8 Q. K7 d$ d$ ]- c1)数据插入,把SQL插入语句传递给cursor的execute函数,可以伴随任何需要的参数。
! }" M D1 B2 b1 B" [1 P" z% ]( y% q! V1 cursor.execute("insert into products(id, name) values ('pyodbc', 'awesome library')")6 ^0 O$ s* j7 g
2 cnxn.commit()
7 _( A3 ~8 D2 i8 i: s
& w2 s J! z4 D1 q0 Y- c1 cursor.execute("insert into products(id, name) values (?, ?)", 'pyodbc', 'awesome library')1 \) y+ ]* S: W& b; K
2 cnxn.commit()
) H8 Y% Q7 J, E9 C) Q' L+ I; K3 \' C/ @' l6 f! x
注意调用cnxn.commit()函数:你必须调用commit函数,否者你对数据库的所有操作将会失效!当断开连接时,所有悬挂的修改将会被重置。这很容易导致出错,所以你必须记得调用commit函数。2 Y! K8 ^/ x! ~1 p0 {% O
]( p: m# g7 M; ?6 b. ~ J5、数据修改和删除
) @ |, H8 V" \9 o+ B% g" u) M$ }6 v3 v+ _
1)数据修改和删除也是跟上面的操作一样,把SQL语句传递给execute函数。但是我们常常想知道数据修改和删除时,到底影响了多少条记录,这个时候你可以使用cursor.rowcount的返回值。" G7 ~; k6 z$ v: O2 I3 Z2 a1 ]) M
1 cursor.execute("delete from products where id <> ?", 'pyodbc')8 }& L5 b6 i! Q: E+ l B. p
2 print cursor.rowcount, 'products deleted'- q8 @3 ~! u; w7 S: c
3 cnxn.commit()
6 p; R1 s' n9 m$ z5 A; u, K/ K) J
$ G4 u, p7 M7 C5 ?& L! P2)由于execute函数总是返回cursor,所以有时候你也可以看到像这样的语句:(注意rowcount放在最后面): Z$ s' |7 M1 V1 J
1 deleted = cursor.execute("delete from products where id <> 'pyodbc'").rowcount
/ V$ D2 P$ x. E" I- b8 I: @2 cnxn.commit()
1 ?: N$ H- ?; D! p$ o. D g9 F& J; Z. _0 x2 _
同样要注意调用cnxn.commit()函数
) ~ g7 O; c) L# N! o2 o
y$ s! @+ Q4 p2 Z6、小窍门5 v/ J9 C; o& y- T1 D# C
- C& [' Z! h) t' i! V* y9 @ q* A' M
1)由于使用单引号的SQL语句是有效的,那么双引号也同样是有效的:9 ^1 i% X- A- _4 G) Q
1 deleted = cursor.execute("delete from products where id <> 'pyodbc'").rowcount
6 i6 b( l/ a" _& t) C- h& x* Z; ?9 }) ?5 ~" v( U* _* Q
2)假如你使用的是三引号,那么你也可以这样使用:
1 n9 s9 R: X' y4 M! R1 deleted = cursor.execute("""
8 {4 z* I0 B8 [ X8 \2 C' [2 delete$ `% o% k) z$ z4 ]( m
3 from products
4 W0 N# B; X" G Z4 where id <> 'pyodbc'
# P6 \" S% h$ h; [5 """).rowcount! ^# S3 y1 ^; ^/ F5 z0 N
0 D( B a! H1 m, O7 T7 l& b
3)有些数据库(比如SQL Server)在计数时并没有产生列名,这种情况下,你想访问数据就必须使用下标。当然你也可以使用“as”关键字来取个列名(下面SQL语句的“as name-count”)+ `0 O4 ~# ?: e& B8 L. v) Z3 p8 Y
1 row = cursor.execute("select count(*) as user_count from users").fetchone()4 c( u! _0 ~4 ~2 A
2 print '%s users' % row.user_count
( c/ M% i6 s) m9 w F) |) }/ i: u; J# y1 c1 f
4)假如你只是需要一个值,那么你可以在同一个行局中使用fetch函数来获取行和第一个列的所有数据。
! x+ E8 k9 D3 x3 g1 count = cursor.execute("select count(*) from users").fetchone()[0]2 J, o9 m/ g$ c8 K" G+ M8 B3 L
2 print '%s users' % count
& O" M$ a1 T2 y% K! p/ F$ x P
2 p+ {2 y& j2 {- l如果列为空,将会导致该语句不能运行。fetchone()函数返回None,而你将会获取一个错误:NoneType不支持下标。如果有一个默认值,你能常常使用ISNULL,或者在SQL数据库直接合并NULLs来覆盖掉默认值。
% g6 j( N( F( T; D1 maxid = cursor.execute("select coalesce(max(id), 0) from users").fetchone()[0]
/ b, @) r5 L- i0 E( F h0 t+ O8 [( H$ H/ ~% M2 k) ^/ B) m
在这个例子里面,如果max(id)返回NULL,coalesce(max(id),0)将导致查询的值为0。 |
zan
|