我有一个从get检索的关联数组,我想使用数组中的数据生成sql查询字符串的“where子句”。
$get_array = ['title'=>'abc', 'author'=>'John']
我创建了一个模板数组,其中包含不同字符串的不同字符串,然后通过get数组循环生成子句数组:
$tpl = ['title' => 'title LIKE ?',
'author' => 'author LIKE ?',
];
$where_clause_array = [];
$binding_array = [];
foreach ($get_array as $field_name => $field_value){
foreach ($tpl as $table_field_title => $tpl_string) {
if ( $field_name == $table_field_title ) {
$where_clause_array[] = $tpl_string;
$binding_array[] = $field_value;
}
}
}
$clause_string = implode(' AND ', $where_clause_array);
结果我会得到一个像“标题喜欢?和作者喜欢?”这样的字符串。但我遇到的问题是我有一个子句字符串,它取两个值而不是一个:
'year_start=>2000', 'year_end=>2017'
'year BETWEEN ? AND ?'
我无法弄清楚如何将它放入循环中。
答案 0 :(得分:1)
在我们找到解决方案之前,我想指出您不需要嵌套的foreach
语句。您只需要遍历模板中的所有键,因此以下代码将获得与您当前所拥有的相同的结果:
foreach ($tpl as $table_field_title => $tpl_string) {
if (array_key_exists($table_field_title, $get_array)) {
$where_clause_array[] = $tpl_string;
$binding_array[] = $get_array[$table_field_title];
}
}
在此基础上,如果您有任何给定参数的多个值,我们只需要允许您在每次迭代中多次插入$binding_array
。
所以这将完成这项工作:
foreach ($tpl as $table_field_title => $tpl_string) {
if (array_key_exists($table_field_title, $get_array)) {
$where_clause_array[] = $tpl_string;
$field_value = $get_array[$table_field_title];
if (gettype($field_value) != 'array') $field_value = Array($field_value);
foreach ($field_value as $value) {
$binding_array[] = $value;
}
}
}
您只需要调整模板:
$tpl = array('title' => 'title LIKE ?', 'author' => 'author LIKE ?', 'dates' => 'year BETWEEN ? AND ?');
和您的输入数据:
$get_array = array('title' => 'abc', 'author' => 'John', 'dates' => array('2000', '2017'));
最终结果如下:
$clause_string = implode(' AND ', $where_clause_array);
echo $clause_string . '<br>';
var_dump($binding_array);
// title LIKE ? AND author LIKE ? AND year BETWEEN ? AND ?
// array(4) { [0]=> string(3) "abc" [1]=> string(4) "John" [2]=> string(4) "2000" [3]=> string(4) "2017" }
答案 1 :(得分:0)
您不需要使用BETWEEN,因为您在尝试抽象查询构建的同时仍然使用GET参数的非规范化字段名称,它使用起来更简单一年&gt; =?条款和另一年&lt; =?条款分开。
此外,如果您要抽象查询构建,则不必为每个字段定义模板,只需选择默认运算符(例如LIKE),并将其他所有内容视为覆盖
这里是我为您准备的代码示例,它允许您继续使用GET参数,同时允许您只担心定义覆盖(即非标准行为):
<?php
$get_array = [
'title' => 'abc',
'author' => 'John',
'year_start' => '2000'
'year_end' => '2017'
];
$overrides = [
'year_start' => ['column' => 'year', 'operator' => '>='],
'year_end' => ['column' => 'year', 'operator' => '<=']
];
$where_clause_array = [];
$binding_array = [];
foreach ($get_array as $field_name => $field_value){
if(isset($overrides[$field_name])){
$override = (object) $overrides[$field_name]; // Use an object as its syntax for accessing properties is shorter than array (e.g. $object->property vs $object['property'])
$column = $override->column ?: $field_name; // If override has a column name use it, otherwise ues the field name in the GET params
$where_clause_array[] = "{$column} {$override->operator} ?";
}
else{
$where_clause_array[] = "{$field_name} LIKE ?"; // We use LIKE as default operator, but we could use = instead and just LIKE in the overrides instead
}
$binding_array[] = $field_value;
}
$clause_string = implode(' AND ', $where_clause_array);
希望它有所帮助。如果确实如此,请标记已回答的问题,如果您有任何其他问题,请与我们联系。我很乐意为您提供帮助。
答案 2 :(得分:0)
您可以使用array_walk函数。
请尝试使用以下代码在所有条件下获取查询(例如:如果year_start或year_end为null):
$test_array = ['title'=>'abc', 'author'=>'John', 'year_start'=>2000, 'year_end'=>2017];
$tpl = array();
array_walk($test_array, function(&$a, $b) use (&$tpl,&$test_array) {
if($b == 'year_start' || $b == 'year_end'){
if($b == 'year_start' && $a){
if($test_array['year_end'] != NULL){
$tpl['dates'] = 'year BETWEEN ? AND ?';
}else{
$tpl['dates'] = 'year > ?';
}
}
if($b == 'year_end' && $a && !isset($tpl['dates'])){
$tpl['dates'] = 'year < ?';
}
}else{
$tpl[$b] = "$b LIKE ?";
}
});
print_r($tpl);