我有一个数据库表USER_OPTIONS,其中包含应用程序中各种选项的字段,它看起来有效如下:
USER_ID | OPTION_1 | OPTION_2 | OPTION_3 | ... | OPTION 20
----------------------------------------------------------
100 | true | true | false | ... | false
101 | true | true | false | ... | false
102 | false | false | false | ... | true
... etc etc
我的应用程序然后想要触发一个AJAX请求来调整这个表。
通过AJAX发送的信息是一组已更改的数据库字段及其新值(采用JSON格式),例如
$my_new_settings === {
'OPTION_1' : 'false',
'OPTION_2' : 'false'
'OPTION_20' : 'true'
}
我的计划是使用参数化的SQL查询
$query_string = "UPDATE `USER_OPTIONS`
SET ? = ?
WHERE
`USER_ID` = ?
LIMIT 1 ;";
$my_user_id = 100;
$my_field_for_updating = "OPTION_1";
$my_new_field_value = "false";
if ( $query = $mysqli->prepare($query_string) ) {
$query->bind_param("sss", $my_field_for_updating, $my_new_field_value, $my_user_id);
$query->execute();
$query->close();
}
然后遍历关联数组以从$my_field_for_updating
抓取另一对$my_new_field_value
和$my_new_settings
。
然而
我随后discovered the following in the php.net manual:
(“markers”是用于参数化SQL查询中“?”变量的术语)
注意:
标记仅在SQL语句的某些位置是合法的。对于 例如,它们被允许在INSERT语句的VALUES()列表中 (指定行的列值),或与列进行比较 在WHERE子句中指定比较值。
但是,不允许使用标识符(例如表格或列) 名称,在选择列表中,用于命名要由a返回的列 SELECT语句,或指定二元运算符的两个操作数 例如=等号。后一种限制是必要的,因为 无法确定参数类型。不是 允许比较标记与NULL?也是NULL。一般来说, 参数仅在数据操作语言(DML)中是合法的 语句,而不是数据定义语言(DDL)语句。
这破坏了我提出的解决方案。
我的下一个想法是让SQL查询更新数据库中的所有字段,但只包含新更新的字段值。但是我发现这需要一个神奇的“无所事事”变量来为我没有数据的字段分配“标记”。
$query_string = "UPDATE `USER_OPTIONS`
SET `OPTION_1` = ?,
SET `OPTION_2` = ?,
SET `OPTION_3` = ?,
...
SET `OPTION_20` = ?
WHERE
`USER_ID` = ?
LIMIT 1 ;";
$my_user_id = 100;
$my_new_OPTION_1_value = 'false';
$my_new_OPTION_2_value = 'false';
$my_new_OPTION_20_value = 'true';
$magic_do_nothing_value = ????;
if ( $query = $mysqli->prepare($query_string) ) {
$query->bind_param("sssssssssssssssssssss",
$my_new_OPTION_1_value,
$my_new_OPTION_2_value,
$magic_do_nothing_value,
$magic_do_nothing_value,
...
$magic_do_nothing_value,
$my_new_OPTION_20_value,
$my_user_id
);
$query->execute();
$query->close();
}
但是,我不知道$magic_do_nothing_value
可能实际上是什么(并且发现很难谷歌)。我尝试的所有内容都会引发错误或被解释为“假”。
所以我的第一个问题是:MYSQL数据库是否接受“什么都不做”的信号?
假设没有并继续前进,我的下一个想法就是将所有当前值拖出数据库中给定的USER_ID
,并使用$my_new_settings
中的更改修改这些值然后使用所有字段相应地更新数据库。
然而,这似乎是很多不必要的工作,特别是与我的第一个解决方案相比。
这导致我在这里要求更好的一个!
非常感谢您的任何想法,我真的很想听听他们的意见。这是在PHP 5.2和基本的MySQL 5.0.92数据库上运行。
答案 0 :(得分:1)
我只是动态地构建SQL,然后像你已经那样绑定参数值。下面是一个使用类来处理动态数量参数的示例(从PHP文档中获取的类)。请注意我没有测试过代码,但无论如何都应该清楚逻辑。
// This class will store the value for each query parameter
class BindParam {
private $values = array(), $types = '';
public function add($type, &$value) {
$this->values[] = $value;
$this->types .= $type;
}
public function get() {
return array_merge(array($this->types), $this->values);
}
}
$my_new_settings = array(
'OPTION_1' => 'false',
'OPTION_2' => 'false',
'OPTION_20' => 'true',
)
$bind_param = new BindParam();
$query_arr = array("UPDATE `USER_OPTIONS`");
// This loop will build the query and store each parameter value in bin_param instance
foreach($my_new_settings as $field_name => $field_value) {
$query_arr[] = sprintf('`%s` = ?', $field_name);
$bind_param->add('s', $field_value);
}
$query_arr[] = 'WHERE `USER_ID` = ?';
$query_arr[] = 'LIMIT 1 ;";
// Put all pieces together, forming an SQL command
$query_string = implode(' ', $query_arr);
$my_user_id = 100;
$my_field_for_updating = "OPTION_1";
$my_new_field_value = "false";
if($query = $mysqli->prepare($query_string)) {
// Bind all parameter values saved earlier
call_user_func_array(array($query, 'bind_param'), $bind_param->get())
$query->execute();
$query->close();
}
答案 1 :(得分:0)
抱歉,我还没有开始使用mysli或PDO(懒惰我:)) 但是当我需要插入或更新mysql表时,我实现了这个功能。 您可能因为基于mysqli的用法而无法直接使用,但可能会给您一个想法。 查找表的字段名并将它们与给定的数组键名匹配(即使使用指定的前缀),还需要在$ sql_condition中指示更新的关键字段,并为过滤要插入的不需要的数据使用$ exceptions。
在我的使用中,键名以" _"开头。 如果以" t _&#34开头;自动被忽略。
function q_put2($data_array=array() ,$table, $exceptions = '', $sql_type = 'insert', $sql_condition = NULL) {
if($sql_condition!=NULL) $table_columns_filter=$sql_condition;
else $table_columns_filter="";
$table_columns_qs="SHOW COLUMNS FROM $table ;";
$table_columns_rs=mysql_query($table_columns_qs);
while ($row=mysql_fetch_row($table_columns_rs)){
$table_columns[]=$row[0];
}
$fields = '';$values = '';
foreach ($data_array as $field => $value) {
if(substr($field,0,4)=="the_")$field=substr($field,4);
if(substr($field,0,2)!="t_" && !strstr($exceptions,$field) && in_array($field,$table_columns)){
$value = mysql_real_escape_string($value);
if ($sql_type == 'insert') {
$fields .= "$field, ";
$values .= "'$value', ";
}
else {
$fields .= "$field = '$value', ";
}
}
}
$fields = preg_replace('/, $/', '', $fields);
$values = preg_replace('/, $/', '', $values);
if ($sql_type == 'insert') {
$sql = "INSERT INTO $table ($fields) VALUES ($values)";
}
elseif ($sql_type == 'update') {
if (!isset($sql_condition)) {
echo 'ERROR: You must enter a sql condition!';
exit;
}
$sql = "UPDATE $table SET $fields WHERE $sql_condition";}
else {
echo 'ERROR: Invalid input for argument $sql_type: must be "insert" or "update"';
exit;
}
if ($q_select_rs=mysql_query($sql)) {
return true;
}
else
{
return false;
}
}