我有一个包含树数据的平面数组。树可以是任意长度和深度的用户需要。每个节点有以下数据:
id: 1,
parent: 0,
id: 2,
parent: 1,
equation: 'user.id = 1'
id: 3,
parent: 2,
equation: 'user.id <> 2'
id: 4,
parent: 1,
equation: 'user.id = 4'
我需要设计的是一个算法,把这个数组变成一个字符串,包含一个mysql子句类似:
WHERE ( user.id = 1 AND user.id <> 2 ) OR user.id = 4
同样,我不能限制这个查询中的逻辑可能变得多么复杂,我只需要允许任何可能性,所以我可能需要将数据转换为关联数组并递归地处理它。
查询的每个部分都由一个接口生成,用户可以在该接口中为其数据库中的用户创建分段规则。因此,他们可能希望选择以下用户:
WHERE user.id = 3 AND user.id != 4 AND user.date_of_birth < 1234567 AND user.date_of_birth > 7654321 AND user.last_purchased_date > 1234567;
我需要使用这个数据源生成的
id: 1,
parent: 0,
id: 2,
parent: 1,
equation: 'user.id = 3'
id: 3,
parent: 2,
equation: 'user.id != 4'
id: 4,
parent: 3,
equation: 'user.date_of_birth < 1234567'
id: 5,
parent: 4,
equation: 'user.date_of_birth > 7654321'
id: 5,
parent: 5,
equation: 'user.last_purchase_date > 1234567'
您可以从数据源中看到,子元素表示AND(子节点添加AND子句),兄弟元素表示OR。即它们具有相同的父元素:
id: 1,
parent: 0,
id: 2,
parent: 1,
equation: 'users.id = 3'
id: 3,
parent: 1,
equation: 'users.id = 4'
这将导致一个OR语句
WHERE user.id = 3 OR user.id = 4
树/数据源可以有任意数量的节点,包含任意数量的方程,我需要使用这个数据结构构建一个查询字符串来表示and/OR组合。
我有点不知道从哪里开始使用这个算法
这样做很有趣!
$test=[ ['id'=> 1,'parent'=> 0],
['id'=> 2, 'parent'=> 1, 'equation'=> 'users.id = 1'],
['id'=> 3, 'parent'=> 2, 'equation'=> 'users.id <> 2'],
['id'=> 4, 'parent'=> 1, 'equation'=> 'users.id = 4']
];
$in_where=[];
echo whereFromArray($test,$in_where);
function whereFromArray($array=[],&$in_where)
{
$return='';
foreach ($array as $key => $value) {
$result=search($array, 'parent', $value['id']);
if (count($result)) {//has children
$return.= 'OR ('. str_replace('OR ', 'AND ', whereFromArray($result,$in_where)) .') ';
}elseif(!in_array($value['id'], $in_where)){
$return.= 'OR '.$value['equation'].' ';
$in_where[]=$value['id'];
}
}
return ltrim(ltrim($return,'AND '),'OR ');
}
function search($array, $key, $value)
{
$results = array();
if (is_array($array)) {
foreach ($array as $subarray) {
if (isset($subarray[$key]) && $subarray[$key] === $value) {
$results[] = $subarray;
}
}
}
return $results;
}
所以这个函数将构建一个数组,所有子句元素都在正确的位置,我只需要内爆数组。也可以用一个连接的字符串来完成。
function where_builder( $elements = array(), &$clause = array(), $index = 0)
{
//
$element_children = $this->return_array_where( $elements, 'parent', $elements[$index]['id'] );
//
$x=0;
foreach( $element_children as $key => $value )
{
if( $x > 0 )
array_push( $clause, ' OR ' );
if( count( $element_children ) > 1 )
array_push( $clause, ' ( ' );
//
$element_grandchildren = $this->return_array_where( $elements, 'parent', $value['id'] );
//
array_push( $clause, $value['equation'] );
//
if( count( $element_grandchildren ) > 0 )
{
array_push( $clause, ' AND ' );
$pointer = $this->get_first_key_where( $elements, 'id', $value['id'] );
$this->where_builder( $elements, $clause, $pointer );
}
if( count( $element_children ) > 1 )
array_push( $clause, ' ) ' );
$x++;
}
return $clause;
}