2011-06-03 83 views
5

發佈此問題MySQL update or insert or die query後我已更改爲使用PDO,但我在使用重複密鑰更新短語時遇到了一些問題。PDO在重複密鑰更新上插入

這裏是我的陣列數據

array(114) { 
["fname"]=> 
string(6) "Bryana" 
["lname"]=> 
string(6) "Greene" 
["m080"]=> 
string(1) "c" 
["t080"]=> 
string(1) "-" 
["w080"]=> 
string(1) "-" 
["r080"]=> 
["notes"]=> 
string(4) "yoyo"} 

在現實中的例子也有113場,但我不想浪費他們展示在這裏的所有空間。我目前正試圖通過下面的代碼

try { 
    $dbh = new PDO('login info here'); 
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
    $stmt = $dbh->prepare(
     'INSERT INTO fhours ('.implode(",", array_keys($faculty)).')'. 
     ' VALUES (:'.implode(",:", array_keys($faculty)).')'. 
     ' ON DUPLICATE KEY UPDATE :fieldlist'); 

    $stmt->bindParam(':field_list', $field_list); 

    foreach($faculty as $key=>$val){ 
     $stmt->bindParam(':'.$key, $val); 
     $fields[] = sprintf("%s = :%s", $key, $key); 
    } 
    $field_list = join(',', $fields); 
    //echo $stmt->debugDumpParams(); 
    $stmt->execute(); 
} 
catch(PDOException $e){ 
    echo $e->getMessage(); 
    exit(); 
} 

,我發現了無效的參數號插入/更新到我的數據庫:參數沒有被定義的錯誤消息。我很確定我的問題在於ON DUPLICATE KEY UPDATE :fieldlist');,但我做了很多不同的嘗試,但都沒有成功。我應該再使用ON DUPLICATE KEY UPDATE了嗎?

而且,我是新來的:和::語法,並:name意味着它是一個命名的變量有點像$name和不PDOStatement::bindValue種像PDOStatement->bindValue

編輯

針對前兩種意見在下面,我正是如此更新的代碼(但仍無濟於事,該debugDumpParams說我沒有PARAMS)。另外,爲什麼要創建$array_of_parameters,當它變成與$faculty開頭的完全相同的數組?

//grab form data 
$faculty = $_POST; 
$fname = $_POST['fname']; 
$lname = $_POST['lname']; 
//delete the submit button from array 
unset($faculty['submit']); 
$array_of_parameters = array(); 
foreach($faculty as $key=>$val){ 
     $array_of_parameters[$key] = $val; 
     $fields[] = sprintf("%s=?", $key); 
} 
$field_list = join(',', $fields); 

try { 
    $dbh = new PDO('mysql:host=localhost;dbname=kiosk', 'kiosk', 'K10$k'); 
    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 

    $update = 'UPDATE fhours SET '.$field_list. 'WHERE fname="'.$fname.'" AND '. 
         'lname="'.$lname.'"'; 
    $stmt = $dbh->prepare($update); 
    //echo $stmt->debugDumpParams(); 
    $stmt->execute(array($array_of_parameters)); 

    if($stmt->rowCount() == 0){ 
     $insert = 'INSERT INTO fhours ('.implode(",", array_keys($faculty)).')'. 
        ' VALUES (:'.implode(",:", array_keys($faculty)).')'; 
     $stmt = $dbh->prepare($insert); 
     $stmt->execute(array($array_of_parameters)); 
    } 
} 
catch(PDOException $e){ 
    echo $e->getMessage(); 
    exit(); 
} 

$dbh=null; 
+0

之所以要創建'$ array_of_parameters'是因爲在你的第一次迭代中,您使用的約束PARAMS對於'ON DUPLICATE KEY'子句和'INSERT VALUES()'。它們都必須在傳遞給execute()的同一個數組中進行。第一次使用'$ array_of_parameters'調用execute()時,您的UPDATE語句中沒有使用任何參數。此外,你已經將數組包裹在另一個'array()'中,這是不必要的。 – 2011-06-03 20:42:24

+0

你先用UPDATE語句做SQL字符串連接,然後傳遞給'prepare()',所以它仍然容易被注入。有關更多信息,請參閱我的答案中的編輯。 – 2011-06-03 20:43:14

+0

您可能需要在'SET'子句中的逗號分隔字段之間留出空格 - 我不記得是否有效省略空格。使用逗號空格加入他們$ field_list = join(',',$ fields);' – 2011-06-03 20:49:18

回答

2

什麼你試圖做的是動態構建SQL字符串會變成參數化。 :paramname參數預計爲映射到列值的單個值,其中子句參數等。相反,您已使用$fields[] = sprintf("%s = :%s", $key, $key);創建一個字段:paramname以便插入查詢。這在參數化語句中不起作用。

而不是做ON DUPLICATE KEY UPDATE :fieldlist,你應該建立整個sql字符串,然後將它傳遞到prepare()

然後而非使用bindParam()方法給每個一個可單獨結合,可以使用替代的語法來​​在預期的參數值的數組來傳遞。它們需要按照正確的順序排列,或者使用與SQL中的參數:param相同的名稱。See the docs for more info and examples.

$array_of_parameters = array(); 
foreach($faculty as $key=>$val){ 
    $array_of_parameters[$key] = $val); 
} 
$stmt->execute($array_of_parameters); 

編輯要正確使用參數在UPDATE聲明中,像這樣做:

// Create your $field_list before attempting to create the SQL statement 
$field_list = join(',', $fields); 

$update = 'UPDATE fhours SET '.$field_list. 'WHERE fname=:fname AND lname=:lname'; 
// Here, echo out $update to make sure it looks correct 

// Then add the fname and lname parameters onto your array of params 
$array_of_parameters[] = $_POST['fname']; 
$array_of_parameters[] = $_POST['lname']; 

// Now that your parameters array includes all the faculty in the correct order and the fname & lname, 
// you can execute it. 
$stmt->prepare($update); 
$stmt->execute($array_of_parameters); 
+0

邁克爾,非常感謝你的幫助。代碼現在全部運行。 – Michael 2011-06-06 16:02:24

2

冒號前綴的名稱只不過是指定的佔位符。當你去綁定你的params時,你只需將你的佔位符綁定到一些任意的值。

ON DUPLICATE KEY UPDATE是不是很多的DBMS友好,但如果你連接到一個兼容的數據庫它應該工作(因爲我不相信PDO會阻止所有這些,但我可能是錯的)。我不會僅僅爲了便攜性而使用它。你可能想檢查你是如何綁定你的字段列表的,但是bindparam只應該做一個參數,而這些是colums,不應該像引用值一樣引用(綁定參數將會這樣做)。

我通過運行最多兩個查詢來設計插入:更新然後插入。我將首先更新並檢查更新的行數是否大於0.如果受影響的行是0,請運行插入。

只是一個空閒的評論,113場是很多領域,如果你不小心,你可能會受到一些表性能

+0

表格是週一至週五上午8點至下午6點30分的表格,間隔爲30米,供教師輸入辦公時間。我願意接受關於數據庫設計的其他想法,但這是另一個主題。 – Michael 2011-06-03 18:38:47