|
我已经看过SQL主键约束,尽管不存在记录,所以SO上所有问题中的哪个似乎最接近我的问题,但并不相同。
, a4 P/ S. Z6 S- A9 j4 h7 U毫无疑问,我可能正在做一些愚蠢的事情,但是这里有:
- w% j3 j& R1 a0 W% V' e" G7 n我正在尝试编写一个脚本(用php编写),该脚本将从任何给定的PDO数据库迁移数据(没有结构,它假定结构已经完成)到任何其他给定的PDO数据库-
6 x6 t7 F# r3 h C3 H4 t在我的情况下,我正在sqlite3上对其进行测试- > MySQL。
+ E8 F3 }0 d2 e: Z- Z当我在测试数据库上运行脚本时,我收到“完整性约束冲突:1062项“ PRIMARY”的重复项“
6 H' R0 s( K0 F1””,我不太了解,因为表中没有数据(即使在脚本运行之前也是如此) DELETE语句)。& P a2 i$ s4 ?2 a p. }
我假设这与主键是auto_increment有关,但是我尝试将下一个增量值设置为除要插入的任何值之外的其他值(认为我尝试将其设置为80)-没什么区别。0 T+ r- I/ v/ @5 {9 E* N
我一直在寻找一种在交易过程中禁用auto_increment的方法,但没有事先更改表,然后再更改回去的方法,我想不出办法-
: d7 j4 L, ~- _9 m& u- q" {) ]更改整个表似乎是错误的,我并不想参与任何DDL。
0 B4 Q# p+ [" P- V/ t- p# Y0 g 1 setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
" y3 c; e/ H K0 Q: Z; |' X" a2 m8 @ 201 R% x I" i b2 i% ` O
21 // connect to target
9 T- D( V' c/ c 22 $target = new PDO($target_dsn, $target_username, $target_password);( V2 a. K+ V7 c J1 [6 M
23 $target->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
% B K( d8 V/ q/ { 24
0 P, S4 ]0 g- e" F; k 25 //TODO Generalise this statement to all database types.2 u$ t/ i! k! r- F- ?/ I5 C
26 $stmt = $source->prepare("SELECT * FROM sqlite_master WHERE type='table';");
- x0 ^: ?9 U) w' I) R$ h 27 $stmt->execute();7 X: J) k3 d5 N8 D
28
8 H( L; E" l* `0 S' F 29 // get all tables
) t$ y: d4 T E" v3 x 30 while($tablerow = $stmt->fetch(PDO::FETCH_ASSOC))
) E B. z8 x! H. D- j" t3 a 31 {( ]. C& [6 `( M/ ~3 m) P
32 // TODO Generalise these statements to all database types.
" E, J/ Y4 B' o3 u, H 33 $transfer_data[$tablerow['tbl_name']] = array();
: x( A0 \( {2 {2 l9 v" f- D4 { 34 $table_data[$tablerow['tbl_name']] = array();
1 I6 _( |# K* y! V 35 }% T! E3 F* p4 N0 J& g8 V
36 $stmt->closeCursor();, [: U2 k! F9 @7 N0 `- N- m9 @
37
& V1 d6 P% ]% O, h; C- t& j 38 // for each table, load data
# y# b; c) C" c1 G$ j 39 foreach($transfer_data as $tablename => $void)9 p2 G! _) s3 x: m+ b' t4 M
40 {
% K; T2 h+ h: G8 N: f q( M 41 $stmt = $source->prepare("SELECT * FROM $tablename;");
S8 y6 E5 g- ~8 v( ^+ d 42 $stmt->execute();
% ?4 p( v* M9 E$ f% R! p 43 // load data row at a time/ s) C5 c0 a6 ?' b; K. d1 ~
44 while($datarow = $stmt->fetch(PDO::FETCH_ASSOC))# i8 P7 N4 E1 x) b# U
45 {7 D+ G/ p2 h3 ?0 k
46 // store data for later
4 y& `! V0 C. S) W/ p" G' Q 47 $transfer_data[$tablename][] = $datarow;2 X- s$ I. @6 l
48 // if we haven't gained column data yet, do so now, P, w* q+ g x9 X" a) E
49 if(!array_key_exists($tablename,$table_data))
8 r" @7 Q' O. T, k, J 50 {
- `. p% i3 A* ^4 C& ` 51 $t_data = array();: t- w3 i1 |: L) o/ f
52 foreach($datarow as $colname => $void)
9 R) c* S- r7 A- u% a, o( r. b 53 {7 ]) m; t% M3 ~' X: k% Q/ i
54 $t_data[] = $colname;
6 m( b+ v J; H4 i; d9 ]: @ 55 }7 |$ s) |' ^+ ^7 }' r
56 $table_data[$tablename] = $t_data;+ g' Y' l/ E( z, W
57 }
% a" r- b" G7 j" k 58 }4 Y4 v6 ~. X2 @/ r. M1 ^7 p
59 $stmt->closeCursor();. Q" O V1 j$ [! Y f% i/ o
60 echo "Read $tablename\n";" c5 l( H, h' w
61 }9 n9 b! T" i8 U' {1 ~, ^
626 s( M) C; d0 i6 M2 V
63 //start a transaction (if driver supports transactions / if not then this is noop)" X* n+ J$ O; K1 b& o" b8 e5 n
64 $target->beginTransaction();
( d+ G; J* W* i5 ?& i& c& \9 i x 65 // for each table clear existing data and insert copied data+ u9 e' o7 T. `, y& R
66 foreach($table_data as $tablename => $columns)
3 p) f1 M" z& g i$ D8 h 67 {4 |' _1 F7 Q; C" Z5 {( o
68 // not using an empty/truncate because mysql and possibly others autocommit
4 \; E$ ?9 d' ~ 69 $stmt = $target->prepare("DELETE FROM $tablename;");: x# N Q# m1 L5 D- \
70 $stmt->execute();
. l. a6 Q! N6 x! q6 N" B! J) L 71 $stmt->closeCursor();' ^$ n. S0 F4 L. {: G
72
4 v, u" C1 W$ n0 Y! q2 F 73 // prepare the insert statement - we don't know how many columns so is dynamic, y: ~" E& M' `- H
74 $querystr = "INSERT INTO $tablename (".join(", ",$columns).") VALUES (";
5 Z1 I3 O6 [5 M/ U" m% q5 M 75 foreach($columns as $k => $column); z7 U9 `6 M! f8 C% M" b
76 {, J) q, N1 K: l( Q( W- p
77 $columns[$k] = ':'.$column;
1 b% z. C; Z! I9 T0 \ 78 }
& A4 Q% E) _; J8 s8 K0 a 79 // using named placeholders so order doesn't matter
Y7 R, ? ^$ E3 }% ~ 80 $querystr = $querystr.join(", ",$columns).");";1 |5 {: ~) H( i, }
81 $stmt = $target->prepare($querystr);) u S* u. A# j; j6 T' [% Z' j
82 //echo "Using: $querystr\n";
5 {. k+ K7 h4 y% K 83 $rowcount = 0;
. C& X, l' ?, w; m5 `5 \" b 84 // for each row of data, bind data and execute insert statement
& T! F. r, O7 T3 t) y) C( x# L 85 foreach($transfer_data[$tablename] as $rowdata). [) l4 p; ~% U, w) G" n B
86 {
, S5 H* o, Z e. `& I# \ 87 foreach($rowdata as $rowname => $rowvalue). S0 w8 e1 p, @# }
88 {. X3 m* [! R+ H$ l; @2 q2 |4 g" }2 F m
89 $stmt->bindParam(':'.$rowname, $rowvalue);( l1 x# ~$ r- p) C ?
90 }1 D7 _. J) o+ R. u7 o/ F: \$ O
91 $stmt->execute();
. a3 h: L3 y- k, h3 |% Y" M 92 $stmt->closeCursor();
; s7 q# ?) Y! N2 E* Q) w& U 93 $rowcount++;
1 k* ?0 b3 z- n- H4 z2 c 94 }, R6 |) v5 {8 L, c4 o0 l' D
95 echo "Written $rowcount rows to $tablename\n";
. A+ F. L% l( x3 M; Y4 H, u" v& a 96 }
. U, s2 n1 ?5 E% \% U( v 97 $target->commit();
* v/ `2 H2 k+ I7 e* k 98! C" c/ v# g1 e0 F' E
99 }9 K% r4 h) @( V' n: a
100 catch (PDOException $e)
' A. i6 b5 i4 m9 w: {5 @* ^101 {
% L) B$ O5 w+ c( n3 ?$ @4 J102 echo 'PDO Error: '.get_class($e).' - '.$e->getMessage()."\n";5 t* j2 b! o6 v3 Y, b
103 echo 'Query String was: '.$querystr."\nData:\n";
( r) d$ _) v- [+ P) c, ^104 var_export($transfer_data[$tablename]);
: ]( E$ D1 [, B' o2 e8 H105 if($target->inTransaction()){6 u; L0 G. V ~! J' H& n X
106 $target->rollBack();
' B0 f5 P/ u% H( F7 O( Z3 [3 v! A107 }
) J7 U2 } D$ c/ u2 X! p108 } c* C0 q. g: U/ R$ |2 m
109
: q9 s. ?0 ]: h; [) u9 C. p2 m现在我的目标数据库中有一个表,该表是:
# f$ d8 q5 z6 l, n8 U& T+-------------------+------------------+------+-----+---------+----------------+* j5 Z. f9 D6 H7 k+ o, a: ]
| Field | Type | Null | Key | Default | Extra |/ A1 n& d$ D! I+ U" I
+-------------------+------------------+------+-----+---------+----------------+2 _# O( j j7 e' Z9 P) D6 \/ ~
| channel_id | int(11) | NO | PRI | NULL | auto_increment |5 B, D, f2 c6 S1 A W: O( }
| channel_parent_id | int(10) unsigned | YES | | NULL | |# V& { `, m5 h+ C( ?3 S
| server_id | int(10) unsigned | NO | MUL | NULL | |# N! v- b h) s1 `
+-------------------+------------------+------+-----+---------+----------------+8 O5 E. ]5 {/ A
输出为:7 F5 ?, |/ D4 C
PDO Error: PDOException - SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1' for key 'PRIMARY'
2 L `$ Y/ G2 ?! f/ tQuery String was: INSERT INTO channels (channel_id, channel_parent_id, server_id) VALUES (:channel_id, :channel_parent_id, :server_id);( F* W* F2 a" k
Data:
! q E; Y- S6 R9 F i9 Y8 e; Sarray (
" w* `: i- }; f+ ^ 0 =>% l( i+ Y9 U$ j& N- J5 s
array (# N2 s$ b2 U y
'channel_id' => '1',$ G# R. Q# v) P5 g! j7 ~2 `" K
'channel_parent_id' => '0',) m/ K- G- c# s3 ~1 f' F
'server_id' => '1',
C- Z9 M9 u0 h ),, k" W0 I( e5 J' }8 M
1 =>
3 a% O( [% |% C4 q2 T array (
$ M1 g) s* J3 _3 e' k( g) ^ 'channel_id' => '24',5 O* W5 f7 U4 ]' ]' j
'channel_parent_id' => '0'," F# \) e3 i D. n8 o+ J
'server_id' => '1',% `6 e/ g0 N0 O0 Q% v* \- h
),
$ V, N' e% G5 @7 z7 m8 x. @9 P! r 2 =>
y% \' M- P: }0 m: r. F0 S* M# ~# w: ~ array (
% w: u" B" D# K' K+ g' X 'channel_id' => '34',# L _6 e& Y* E1 n0 @: ?
'channel_parent_id' => '0',' g& W0 i7 G, W: A* ]' v
'server_id' => '1',9 Q: j( x, ~; n0 }) h* G
),9 o3 @# p" _" ^2 }) @3 \9 S
# e3 o4 }4 s2 J+ {7 }; F: n/ f解决方案:, D$ P$ l1 b: H7 p; Q' s* ] x! a: h. r
& y; K$ H: o. G, _1 ~0 }: Z
# G' Z% r% q. M& _" f' s8 j1 Y
% F, ?* ]5 q4 ] 很高兴您解决了这个问题。然而,这是为了应对 理由 为什么bindParam()不为你工作。这不是错误,它是通过设计以这种方式工作的。7 ?$ e+ ~6 d( W0 @; N2 [4 N
根据文档: n% A$ f T- U* y5 A6 C
j* _9 G! l. N' [% U& U将PHP变量绑定到用于准备语句的SQL语句中的相应命名或问号占位符。与PDOStatement :: bindValue()不同,该变量被绑定
# T. j9 ~5 x5 O2 b* ]为引用,并且仅在调用PDOStatement :: execute()时进行评估 。" S9 |/ x7 [6 F: v
4 E- }7 H9 q. @3 `! m
(强调我的)0 d' V& ]% l! w) E7 M& ^
考虑到上述情况,这是:
/ i% b# i4 B T+ H5 B: z6 S/ N 87 foreach($rowdata as $rowname => $rowvalue)8 p( O0 A# J- i) b' f
88 {" m! u& O! D/ a+ ]# s V/ A5 h
89 $stmt->bindParam(':'.$rowname, $rowvalue);- a( |& a( D5 T
90 }
9 h8 S/ S+ `% A8 q…将$rowvalue 通过 查询将每个参数绑定到 引用 ,在执行查询时,该 引用 将始终是1(的最后一个元素$rowdata)1 L' N r! r4 V( h
使用它的方式bindParam()可能是这样的:( J* p l' p, N3 S( Y1 B: M
87 foreach($rowdata as $rowname => $rowvalue)
3 g- ^7 l* s/ L2 l% H+ @: D 88 {% Y4 W- j- k/ R0 g3 J" y8 @4 d
89 $stmt->bindParam(':'.$rowname, $rowdata[$rowname]);
, W: t; o1 d" O' ^5 M 90 }6 `, C! l) b5 \( {4 G- c/ Q2 k. Y
…或者,甚至:
4 t$ A- V+ a& I) y2 t& a 87 foreach($rowdata as $rowname => &$rowvalue)3 ?* r( |! _/ H5 s3 P
88 {+ Y0 x8 s) t! ^- B- b
89 $stmt->bindParam(':'.$rowname, $rowvalue);" F `- q+ ~4 a8 {5 k# b* T
90 }
" w4 Y1 C+ } B" [. B…,以便每个参数都引用相应的array 元素 。" ^3 L6 f0 E! x
如上所述,一种替代方法是 _通过值_而不是通过引用bindValue()绑定参数。这意味着将在调用该参数时对其进行评估,而不是在实际需要该参数时(即查询执行)进行评估:__bindValue()% A) e3 T" }6 I* |& t
87 foreach($rowdata as $rowname => $rowvalue)
, P. p! R! V _! o/ I 88 {3 @! H4 U6 a8 b; x8 @
89 $stmt->bindValue(':'.$rowname, $rowvalue);
% @# Z: B* s5 |9 b1 n& @: {8 z" M6 Z 90 }
; l, _5 S4 e5 `4 L当然,另一种选择是输入execute()一组参数,这可以execute()解析绑定部分 (因此是我个人的最爱!) 。 |
|