|
我已经看过SQL主键约束,尽管不存在记录,所以SO上所有问题中的哪个似乎最接近我的问题,但并不相同。
( q% {6 }4 u4 d' s+ N' z" B$ B毫无疑问,我可能正在做一些愚蠢的事情,但是这里有:# }6 [: |4 R( ^! \: o9 p
我正在尝试编写一个脚本(用php编写),该脚本将从任何给定的PDO数据库迁移数据(没有结构,它假定结构已经完成)到任何其他给定的PDO数据库-
! T( \5 B. N" {8 C$ B& [% X, \在我的情况下,我正在sqlite3上对其进行测试- > MySQL。( j ~; J9 l/ ^0 S/ G/ [
当我在测试数据库上运行脚本时,我收到“完整性约束冲突:1062项“ PRIMARY”的重复项“8 G% ^9 `3 K* f8 V! x- z
1””,我不太了解,因为表中没有数据(即使在脚本运行之前也是如此) DELETE语句)。, H" g: e! Z# q z
我假设这与主键是auto_increment有关,但是我尝试将下一个增量值设置为除要插入的任何值之外的其他值(认为我尝试将其设置为80)-没什么区别。4 O! l: N' P- h& a* ^$ a
我一直在寻找一种在交易过程中禁用auto_increment的方法,但没有事先更改表,然后再更改回去的方法,我想不出办法-/ |) j0 A1 C8 i) l3 |
更改整个表似乎是错误的,我并不想参与任何DDL。& B) q; o* F- g" U+ y0 y# N
1 setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);" O }: Y; @) B0 w. M* G
20
9 ^$ Y9 A" d% r: ?+ S; t9 L 21 // connect to target4 T: H* t' p, f8 p
22 $target = new PDO($target_dsn, $target_username, $target_password);% X, @5 v2 }5 j. s3 G
23 $target->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);5 u: D' y" e) f- L9 D3 o! |
24) Y {! b. W8 h; E
25 //TODO Generalise this statement to all database types.
5 j- [/ M3 E c5 W 26 $stmt = $source->prepare("SELECT * FROM sqlite_master WHERE type='table';");
! T: J l2 i# o" P: W/ P4 c 27 $stmt->execute();
S: Q4 n- v" c1 E6 k 28% {% r6 i( B8 W$ p2 d# q
29 // get all tables0 Q1 A0 @2 V0 [" n' u% V- x }
30 while($tablerow = $stmt->fetch(PDO::FETCH_ASSOC))
. R7 o4 e# H/ U2 T& {- j 31 {
* v) H& E( L( r! u9 w9 S 32 // TODO Generalise these statements to all database types.. W3 ~" U7 V" q$ ]4 Y1 M
33 $transfer_data[$tablerow['tbl_name']] = array();9 q& e7 R9 i/ X' i/ o8 ?
34 $table_data[$tablerow['tbl_name']] = array();
* T, W8 x% O. m! l9 } 35 }! V& E |+ x: O7 c6 y( A
36 $stmt->closeCursor();
7 ~' q( `6 z: u4 M( D 377 E- d% ]5 k& s) `
38 // for each table, load data# I* P& I& L8 k& z. m3 e* T
39 foreach($transfer_data as $tablename => $void)' X% {: ]1 r6 V5 ^
40 {
* D) a, Q& x& r6 Q; z# e+ G7 I ^ 41 $stmt = $source->prepare("SELECT * FROM $tablename;");8 Y" j& p) u r5 |! K% L6 P/ R
42 $stmt->execute();5 V) L3 q0 s7 O7 f/ X: c
43 // load data row at a time
' T0 E3 G [) h& F 44 while($datarow = $stmt->fetch(PDO::FETCH_ASSOC))* v2 b1 Y7 W0 I
45 {/ S( A8 `! O$ Z
46 // store data for later
z- g% M- F# j+ }; V) f7 W 47 $transfer_data[$tablename][] = $datarow;3 k3 R, l$ l3 r. P
48 // if we haven't gained column data yet, do so now+ x" c. D7 }& K* q% x
49 if(!array_key_exists($tablename,$table_data))3 a; n( D+ ^( Q, S! m! \
50 {
% B- b) @) U3 D4 t0 v 51 $t_data = array();, C) W9 F4 |$ l$ x/ Y- `
52 foreach($datarow as $colname => $void)1 u" g3 ]5 g8 J
53 {, l# E, ?9 g' h( M
54 $t_data[] = $colname;$ P* }' x7 W3 _* B2 r3 ?
55 }
. J; u% M/ w7 u& C1 i2 t 56 $table_data[$tablename] = $t_data;
- \5 f8 V8 ^( K, F) C+ z 57 }
+ X7 ]5 T: U8 i3 }0 ]6 k" l9 { 58 }
+ M+ h2 ] o8 N6 J+ E 59 $stmt->closeCursor();
7 d" U0 ?) K5 d5 N- U# o 60 echo "Read $tablename\n";
( l, L5 i9 t P 61 }
' d- w. u8 X. Z 620 _- m- @. d0 V$ z" G/ V
63 //start a transaction (if driver supports transactions / if not then this is noop)" B# g2 b& X% b6 O
64 $target->beginTransaction();
# F" f$ W9 s) D \ 65 // for each table clear existing data and insert copied data1 ~9 h) F. y: j0 I- @, ?6 I* u+ B U
66 foreach($table_data as $tablename => $columns)
/ `$ A# S; i) ] 67 {
* f. X5 p5 u1 r% r) Z% ^$ V 68 // not using an empty/truncate because mysql and possibly others autocommit9 ~+ ]" x+ `$ e: {$ M$ {* P
69 $stmt = $target->prepare("DELETE FROM $tablename;");
% Z% R' u! P8 P 70 $stmt->execute();
+ Y! N e' {8 `6 K1 m 71 $stmt->closeCursor();
9 ]) u6 P+ y% ]5 u( F 728 Y! }# M( M5 [# y$ x, j: y
73 // prepare the insert statement - we don't know how many columns so is dynamic
& p9 D3 J. [# P' M5 O+ } 74 $querystr = "INSERT INTO $tablename (".join(", ",$columns).") VALUES (";
! ^; f1 {9 Q, j& R+ h! i4 e. n 75 foreach($columns as $k => $column)3 t6 g+ @8 [; s
76 {
* }/ O' x3 b' Q) _ T4 E& f6 {4 W6 ~& B 77 $columns[$k] = ':'.$column;0 M2 v2 m6 j/ h/ h K& ?; w
78 }
4 e3 t V5 e0 D) V. G: } 79 // using named placeholders so order doesn't matter
2 H; J$ z2 e4 A5 w+ j ]$ q 80 $querystr = $querystr.join(", ",$columns).");";/ S$ l' o2 M9 A7 T
81 $stmt = $target->prepare($querystr);
$ s" F- |% D7 X ?1 a2 Z# t/ i: ^- E 82 //echo "Using: $querystr\n";3 o! s3 R) @) J9 I; k$ y6 |
83 $rowcount = 0;
. C. \' g3 `4 I5 b. U) z 84 // for each row of data, bind data and execute insert statement3 L1 U' }3 O8 w/ C d+ e, S3 o! z
85 foreach($transfer_data[$tablename] as $rowdata)
5 N5 d8 E/ c n3 D 86 {: y. v- d" W; x( X1 J7 S
87 foreach($rowdata as $rowname => $rowvalue)8 Z2 B) X. H+ v/ o% D( v
88 {
* {# Z$ K5 t8 p: H& x 89 $stmt->bindParam(':'.$rowname, $rowvalue);
- t3 q' D$ p0 X s2 U# S4 @6 K 90 }
7 c% } F% \* o9 @3 K 91 $stmt->execute();
1 F- J$ _! I h0 r: S" z7 V 92 $stmt->closeCursor();' p: A3 ]$ k- l/ N$ e. @% s8 E N
93 $rowcount++;8 D* L1 \; N% r
94 }% B5 y6 `4 y$ _: ~/ j3 E
95 echo "Written $rowcount rows to $tablename\n";5 P0 h, ~, O5 ~* J7 [
96 }
+ h1 P2 o" M4 o) I) m# ]& I 97 $target->commit();
; N' E G3 v. Q% U( e3 x 98# u2 V# U+ b& a( c5 n# C+ u9 r
99 }. N/ m& ?' K3 r' _4 i) M3 l
100 catch (PDOException $e)
0 _7 N* m' _7 Q7 A: ^. D2 E101 {
# w) f$ `$ M" M. a2 f102 echo 'PDO Error: '.get_class($e).' - '.$e->getMessage()."\n";) u' r+ ]. y6 N9 r2 d+ v
103 echo 'Query String was: '.$querystr."\nData:\n";
o; P1 C+ q5 o5 a. C' R. L' M: ]104 var_export($transfer_data[$tablename]);6 t E% q/ Y: H; {
105 if($target->inTransaction()){" m, r. |: |- r1 W4 C
106 $target->rollBack();) v6 o; m, C4 O% [' W+ | M. {
107 }
( }6 s+ v8 h- E. J% D4 B6 a6 g$ z* S108 }0 I$ J) I4 Z/ o* @9 `2 D6 ]
109( F* {4 m, h, D6 L" J
现在我的目标数据库中有一个表,该表是:+ f" G1 I& A) I0 w
+-------------------+------------------+------+-----+---------+----------------+) i8 e/ D. x U5 _4 N6 o
| Field | Type | Null | Key | Default | Extra |
* l* L9 b' h& Y+ s9 }" A L5 R+-------------------+------------------+------+-----+---------+----------------+ |% |; {4 O9 ?! J" N
| channel_id | int(11) | NO | PRI | NULL | auto_increment |9 Z! y2 M2 S# D! e( U: F
| channel_parent_id | int(10) unsigned | YES | | NULL | |
0 X5 @0 e7 j9 y2 o1 \| server_id | int(10) unsigned | NO | MUL | NULL | |
! T9 ^( s F0 b8 k9 f) u* K& [% C+-------------------+------------------+------+-----+---------+----------------+
1 x9 l W \: s. j/ J& ]输出为:
+ B: M) }" G* y( q0 g' I YPDO Error: PDOException - SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1' for key 'PRIMARY'
+ M$ s0 | @ JQuery String was: INSERT INTO channels (channel_id, channel_parent_id, server_id) VALUES (:channel_id, :channel_parent_id, :server_id);
- L' Q2 E0 Z" X& O) {5 g! aData:
5 `+ F3 o: M2 K( z2 n: Sarray (3 i( b1 r. R/ M' a2 |/ T/ z: R
0 =>
0 @5 [0 B5 h9 p' M) k array (1 K3 b: e5 s9 `$ x* h: K
'channel_id' => '1',
}2 k4 X6 R8 [3 N, n 'channel_parent_id' => '0',( [+ Z- D) o$ y2 m1 P0 m
'server_id' => '1',. l- [$ M8 J1 r# N# |
),
4 m5 }6 D1 h6 w, i 1 =>5 A7 T, Z1 ~5 o2 D9 o7 W X: ?
array (; t4 s7 F) Y/ Z2 @
'channel_id' => '24',4 u1 ~/ Y! i9 \6 _: |
'channel_parent_id' => '0',$ a8 Z% J( \ E4 ?
'server_id' => '1',
d/ w, b7 f" j K5 h. @# G8 Z; s4 d ),
! T ~) C4 H/ T: g l6 N 2 =># {9 x' y) _% @! _8 v
array (
, p' X) ^% \3 m H 'channel_id' => '34',
6 n$ i+ Q4 N- K! Z$ e 'channel_parent_id' => '0',
% ]+ o c+ D# |9 w* m 'server_id' => '1',& P I+ V0 \4 Y
),
, T" o8 Q, h2 D# T+ |; O / N: K, X, G* C' _3 f
解决方案:0 Q, v8 _0 O Q2 S- O+ d x* O
$ x4 }5 M- |7 `" L% R/ ]" s$ u2 {2 x1 K
6 r' h6 o9 ]8 y) I) a" U$ I
很高兴您解决了这个问题。然而,这是为了应对 理由 为什么bindParam()不为你工作。这不是错误,它是通过设计以这种方式工作的。
! i! h# D3 ~, y) l% f: r根据文档:
" i$ d6 a: M- B: @$ Y% K# |
9 @" X7 t5 H G7 Y; |将PHP变量绑定到用于准备语句的SQL语句中的相应命名或问号占位符。与PDOStatement :: bindValue()不同,该变量被绑定' O* }3 n! y5 Y2 d
为引用,并且仅在调用PDOStatement :: execute()时进行评估 。5 A8 r) }1 `* c) r* V: ]
2 c) {1 F7 ^& M, `7 u/ ?
(强调我的)
( ], z/ Q4 |$ o; k- O考虑到上述情况,这是: {- r( T- x+ d8 C$ d
87 foreach($rowdata as $rowname => $rowvalue)9 B( d; E3 x4 U! @6 y/ f
88 {
: @' D3 y! h- M- s6 K7 |# I6 K 89 $stmt->bindParam(':'.$rowname, $rowvalue);1 C9 ]) W4 F' _
90 }7 t3 }# d- R) a3 x1 I+ ]1 Q6 q" j( c
…将$rowvalue 通过 查询将每个参数绑定到 引用 ,在执行查询时,该 引用 将始终是1(的最后一个元素$rowdata)( g9 f$ Z& }9 |9 M$ o& w
使用它的方式bindParam()可能是这样的:
1 K4 k6 N$ G1 l 87 foreach($rowdata as $rowname => $rowvalue); `4 z& m- |1 Q8 s
88 {5 q" q2 [- F2 Z% c5 f+ ]# |' n
89 $stmt->bindParam(':'.$rowname, $rowdata[$rowname]);, K# ^+ ]- D0 a8 [
90 }( {8 ]( P4 L) p9 W- M% K; O" g3 e# ^$ M
…或者,甚至:
& [7 N" a9 H1 G, o# @6 |( }2 A 87 foreach($rowdata as $rowname => &$rowvalue)# }- D- s7 A9 x1 V2 S5 p2 A* N1 I8 k1 c
88 {
( ^' I' H( \% k% C 89 $stmt->bindParam(':'.$rowname, $rowvalue);
$ I; R* A- ~, J1 N5 T 90 }
* _8 Y9 v. L/ j5 [( M…,以便每个参数都引用相应的array 元素 。
3 a$ z6 A; B3 }2 ]: R7 U* L, N4 R如上所述,一种替代方法是 _通过值_而不是通过引用bindValue()绑定参数。这意味着将在调用该参数时对其进行评估,而不是在实际需要该参数时(即查询执行)进行评估:__bindValue()
X6 t; u5 Z. J a W) A% r | 87 foreach($rowdata as $rowname => $rowvalue)) E; c6 Q9 P, D: P; k( M
88 {8 p( l5 o- `6 P9 [% T( z
89 $stmt->bindValue(':'.$rowname, $rowvalue);" U- _, S# s0 m, P' s3 C3 @! w
90 }
* c8 |7 j; z2 M1 s! G6 k当然,另一种选择是输入execute()一组参数,这可以execute()解析绑定部分 (因此是我个人的最爱!) 。 |
|