- 在线时间
- 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、连接数据库& q, M! U e2 G
) l, Z) a; X- r$ t. P
1)直接连接数据库和创建一个游标(cursor)4 ? `1 }0 c/ t. ~
1 cnxn = pyodbc.connect('DRIVER={SQL Server};SERVER=localhost;DATABASE=testdb;UID=me WD=pass')
$ G. T t+ S8 J! l" m2 cursor = cnxn.cursor()
0 f8 _& t$ R0 r& W0 D/ C
* x8 \$ V! ~7 R7 _8 R2 x: L2)使用DSN连接。通常DSN连接并不需要密码,还是需要提供一个PSW的关键字。
C' k, J, }% N5 r1 cnxn = pyodbc.connect('DSN=test WD=password')# a" L' }, ]2 J; o& A4 a
2 cursor = cnxn.cursor()
. b# d# g* {" n: ?- z9 j2 y( I4 G! d
关于连接函数还有更多的选项,可以在pyodbc文档中的 connect funtion 和 ConnectionStrings查看更多的细节
. C3 s# k, e* j7 W2 I" ]0 ?- j! j8 l; v# ~9 ~/ [% n# ~) w8 a
2、数据查询(SQL语句为 select ...from..where)
( }' e& D$ L- T5 i, |5 k; L+ y* m+ }: u; h6 ^
1)所有的SQL语句都用cursor.execute函数运行。如果语句返回行,比如一个查询语句返回的行,你可以通过游标的fetch函数来获取数据,这些函数有(fetchone,fetchall,fetchmany).如果返回空行,fetchone函数将返回None,而fetchall和fetchmany将返回一个空列。
0 Y5 K0 s' ^! X4 C6 F1 cursor.execute("select user_id, user_name from users"). p7 Y& C' S3 m i: y: P
2 row = cursor.fetchone()
3 t' X+ p8 d4 Y3 if row:
6 U% }" M( G R! @4 print row, J! C( R* J# x6 N6 m& `8 v
! N" z' l# r! Q! J. Z2)Row这个类,类似于一个元组,但是他们也可以通过字段名进行访问。, P8 o4 g$ ]( Y/ }( O9 U! U
1 cursor.execute("select user_id, user_name from users")
) @# T$ n8 f% f2 row = cursor.fetchone(); u V5 |, x9 X
3 print 'name:', row[1] # access by column index
; M. b* N/ I1 y8 R4 print 'name:', row.user_name # or access by name
7 f* _/ S( N* b2 U3 `
# F1 w' {5 F; B$ }2 X! D3)如果所有的行都被检索完,那么fetchone将返回None.& D8 Y1 {- n6 V
1 while 1:: c. c p6 c/ |; ]8 o
2 row = cursor.fetchone() [: B8 N( o) i3 n2 c7 Q, t8 I
3 if not row:# B' D9 d: l% [4 I O! r* C7 {& C( ?
4 break
, P5 E+ P7 D3 V3 ~3 B5 print 'id:', row.user_id; o- H4 `0 y2 s0 d4 M0 ]) r5 K
; ~# J$ X9 n! |$ A, y5 D4)使用fetchall函数时,将返回所有剩下的行,如果是空行,那么将返回一个空列。(如果有很多行,这样做的话将会占用很多内存。未读取的行将会被压缩存放在数据库引擎中,然后由数据库服务器分批发送。一次只读取你需要的行,将会大大节省内存空间)
9 e+ Q$ C* a5 ^* m9 I2 \- \1 cursor.execute("select user_id, user_name from users")
7 v3 w) Z R* u% e, f2 rows = cursor.fetchall()
p4 ^- R @! Q! m3 for row in rows:; t1 N" u) b+ U2 C
4 print row.user_id, row.user_name
) T& c$ E. s7 n0 L9 Z" }) ~4 G2 T
7 q7 z% r2 J( A# E/ L$ G5)如果你打算一次读完所有数据,那么你可以使用cursor本身。8 @( F7 o% V0 d |
1 cursor.execute("select user_id, user_name from users"):% Y; h$ \( S' o+ N" i5 w
2 for row in cursor:, _: l5 w7 S. w& X
3 print row.user_id, row.user_name
' ], h0 m8 J! Y! F) ~! `' X) W" r# `2 R' Q
6)由于cursor.execute返回一个cursor,所以你可以把上面的语句简化成:1 X; ]: y- C2 M! W
1 for row in cursor.execute("select user_id, user_name from users"):
9 @" u) u. V4 W2 print row.user_id, row.user_name- T8 B( y$ n$ `- C; K% f
' S5 B! A. v4 R' R8 o' t
7)有很多SQL语句用单行来写并不是很方便,所以你也可以使用三引号的字符串来写:& f. g& f5 \# H& A; ]
1 cursor.execute("""
0 `8 J: v4 w5 `* n2 select user_id, user_name
7 d9 `0 m7 v9 v/ r3 from users
" H; S" L& k7 N+ l4 where last_logon < '2001-01-01'
1 c: \- q' A1 |. X8 ]. Y! c% z5 and bill_overdue = 'y'
L9 l8 M Z$ @& U6 """)
0 c) n- C; E4 X+ ?& x
7 P# {- ?8 C+ t: S$ D8 N3、参数* j" \; D6 q# r# C
. `3 N2 F* V' ^3 k/ Z4 |, b) r
1)ODBC支持在SQL语句中使用一个问号来作为参数。你可以在SQL语句后面加上值,用来传递给SQL语句中的问号。
8 M# J# `5 ^" w1 cursor.execute("""
9 s* D; B2 z7 G. l2 ?0 ]! Z6 }2 select user_id, user_name
& z4 f7 U% n* Q$ R( G3 from users% `8 ^: u: O* o1 k, ^
4 where last_logon < ?
- M) m( H) u9 J; [" C5 and bill_overdue = ?
9 i% L/ v; r! V& @. v, H6 """, '2001-01-01', 'y')
! \" I' r& V6 P% B9 c E) U. q8 k8 p8 `1 `+ n9 h( h! t# L
这样做比直接把值写在SQL语句中更加安全,这是因为每个参数传递给数据库都是单独进行的。如果你使用不同的参数而运行同样的SQL语句,这样做也更加效率。
7 F9 ^( O, v, r* [+ A7 | y. ]6 f( F( H; y/ N# c
3)python DB API明确说明多参数时可以使用一个序列来传递。pyodbc同样支持:
; O1 h* g- s' h+ @7 r0 q1 cursor.execute(""", X3 L) ?/ H [3 K
2 select user_id, user_name
0 k* L) L+ o2 h3 [' _3 from users! ~% S1 e7 Q. g
4 where last_logon < ?
4 [& E7 r! j2 P# g+ a1 z: V, R5 [$ I, U5 and bill_overdue = ?, t5 t/ N3 i B+ A% h$ s
6 """, ['2001-01-01', 'y'])
" W2 G! z6 \4 z- N) F' U/ k8 B# A% n3 P! s+ V8 ^
1 cursor.execute("select count(*) as user_count from users where age > ?", 21)+ t' k$ e' _. t# K3 r; B; Y3 ^/ ]
2 row = cursor.fetchone()* |4 i# i) u& O- k' g% K
3 print '%d users' % row.user_count( l3 t: e1 M- Y$ ^
H+ @. b2 w$ ?, k2 N% h- K/ l
0 x+ S7 P* u: h% ]$ V5 z9 u3 p+ o' W! {" y
4、数据插入% m8 n. C2 w/ ^+ K* J1 i5 Z: u5 H
+ N- i9 j( A _( e6 {6 b* b- _1)数据插入,把SQL插入语句传递给cursor的execute函数,可以伴随任何需要的参数。+ ~* n+ e1 e) s, d" |
1 cursor.execute("insert into products(id, name) values ('pyodbc', 'awesome library')")5 L. E, e: P: ?8 S
2 cnxn.commit()
" E& ^+ R s) l/ r, I. P; w* F
/ }2 M) X! `8 Y H6 O1 cursor.execute("insert into products(id, name) values (?, ?)", 'pyodbc', 'awesome library')
+ R+ [( S: l/ b2 cnxn.commit()# t5 Z8 L: r0 n
7 w1 q% R0 {0 P8 L注意调用cnxn.commit()函数:你必须调用commit函数,否者你对数据库的所有操作将会失效!当断开连接时,所有悬挂的修改将会被重置。这很容易导致出错,所以你必须记得调用commit函数。- f. y4 U9 M' x$ k [6 r
& g& P# O; b& A5、数据修改和删除2 q0 X& ?1 w" @' `3 U4 [% w
1 ]- X& i) V/ V% w( l6 R9 a
1)数据修改和删除也是跟上面的操作一样,把SQL语句传递给execute函数。但是我们常常想知道数据修改和删除时,到底影响了多少条记录,这个时候你可以使用cursor.rowcount的返回值。% [" _* A0 `1 j( l. S. r
1 cursor.execute("delete from products where id <> ?", 'pyodbc'), o! i; R6 D1 k8 p% z+ _: p+ l; P, {
2 print cursor.rowcount, 'products deleted': a: N7 r* j$ d1 b) z% a- C8 R! r( i
3 cnxn.commit()
: z* @9 g2 ]& }+ U
* F- A) n+ z% m) h& ?$ e; V2)由于execute函数总是返回cursor,所以有时候你也可以看到像这样的语句:(注意rowcount放在最后面)
9 A" `* d" W! \" y$ g c1 deleted = cursor.execute("delete from products where id <> 'pyodbc'").rowcount! \ K+ X' o. Z. P
2 cnxn.commit()9 ^. j! _8 o4 s4 l* }& |
* d, Q0 x; R) ~0 `( ~% t! S: H同样要注意调用cnxn.commit()函数* Y' y) ~3 I" r' C! |' q7 e
4 G! f5 T% Y8 Y' C1 f0 ~
6、小窍门
" A6 X: U9 z2 C* ]5 f) v' h0 i5 P
- t( i: W. Z* M2 L1)由于使用单引号的SQL语句是有效的,那么双引号也同样是有效的:+ s! u! H6 y" p" X9 D- A: x
1 deleted = cursor.execute("delete from products where id <> 'pyodbc'").rowcount; `& f& ^) z4 l8 j0 R
, @8 Y. K) x, |
2)假如你使用的是三引号,那么你也可以这样使用:
- Z1 ^. u0 ^& e+ ?0 C1 deleted = cursor.execute("""( X4 F/ M/ h6 P6 v( `
2 delete
$ z$ y9 a1 {; w# u& w7 W3 J9 l! K) j3 from products! ?( m8 a8 f5 v/ D
4 where id <> 'pyodbc' p, \' }! b* |8 y8 j4 O2 {7 L: c! I! L& r
5 """).rowcount
% P- E- P z% W& I. [
+ U( f, ]$ Z0 s g9 e% W+ m3)有些数据库(比如SQL Server)在计数时并没有产生列名,这种情况下,你想访问数据就必须使用下标。当然你也可以使用“as”关键字来取个列名(下面SQL语句的“as name-count”)
; x8 |. G |, B) D1 row = cursor.execute("select count(*) as user_count from users").fetchone(): k3 ]1 l' w3 V1 U; m
2 print '%s users' % row.user_count
" g' M; Y6 L) ~
4 d; b- e6 O% C+ S- f9 T8 l. Z G4)假如你只是需要一个值,那么你可以在同一个行局中使用fetch函数来获取行和第一个列的所有数据。
4 K/ n0 F, r9 J ~4 Q* a% q# y1 count = cursor.execute("select count(*) from users").fetchone()[0]
& T" y: J+ e& R2 print '%s users' % count2 G5 _- f1 V( `4 w- ]' W
' p$ R9 t* S9 t. N; R7 e( P. \
如果列为空,将会导致该语句不能运行。fetchone()函数返回None,而你将会获取一个错误:NoneType不支持下标。如果有一个默认值,你能常常使用ISNULL,或者在SQL数据库直接合并NULLs来覆盖掉默认值。- P ]0 n0 f7 z. K ]! j P( E
1 maxid = cursor.execute("select coalesce(max(id), 0) from users").fetchone()[0]
& _# S2 C7 r: _2 Q; L! P8 O. e, n& U% p
在这个例子里面,如果max(id)返回NULL,coalesce(max(id),0)将导致查询的值为0。 |
zan
|