2011-06-03 102 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