2012-03-20 6 views
0

私はいくつかの条件を定義するテーブル条件を持っています。 私はいくつかのルールを定義するルールと呼ばれる別のテーブルを持っており、各ルールは多くの条件を持つことができます。しかし、ルールは、このようにグループ化された条件を持つことができなければならない:MySQLとPHP - リンクされたエンティティの論理条件グループ

(condition1) && 
(condition2) && 
    (condition3 
    || condition4 
    || 
     (condition6 && 
     condition7) 
    ) && 
(condition5) 

このネスティングは、それが望んでいるほど深く行くことができますので、私はバインドテーブルにこれら2つのテーブルを結合することができないので、私は考えていました (条件1) "条件1" がIDとなり& &(条件2)& &(condition3 || condition4 ||(condition6 & & condition7))& &(condition5) :実際ようなルール・テーブルにそれを保存します条件1など

私はこの情報をPHPで解析し、何らかの形で文字列全体から論理チェックを作成します。

これはOKのアプローチですか、またはこのようなネストされたバインディングをMySQLで行うためのより良い方法がありますか?私は絶対に、1つのルールでANDサブグループとORサブグループの両方で条件をグループ化する能力を保つ必要があります。私はこのような何かを建設する場合、私は、この構造を使用している場合があります

答えて

1

私は確かに文字列としてあなたの条件を保存する明確な舵取りでしょう。その文字列を解析する必要があります。既存の条件を編集する(または特定の条件などを検索する)場合は、おそらく結び目に縛られてしまいます。

@ tpaksuの解決策にはいくつかの欠陥がありますが、私は確かにツリー構造の何らかの形でそれを保存します。私はこれらの線に沿って何か

ID | Rule_ID | Condition_ID | Parent | Operator | 
------------------------------------------------------------ 
1 | 1   | NULL   | NULL  | AND  | 
2 | 1   | 1    | 1   | NULL  | 
3 | 1   | 2    | 1   | NULL  | 
4 | 1   | NULL   | 1   | OR  | 
5 | 1   | 3    | 4   | NULL  | 
6 | 1   | 4    | 4   | NULL  | 
7 | 1   | NULL   | 4   | AND  | 
8 | 1   | 6    | 7   | NULL  | 
9 | 1   | 7    | 7   | NULL  | 
10 | 1   | 5    | 4   | NULL  | 

私は、これはあなたがモデル化したかった元の論理構造を表していると思いますがお勧めします。これは、同じレベルに条件があり、それぞれの条件がどのブランチに属するかを追跡できる、ツリー内の複数のブランチを持つことができるということです。テーブル内のエントリの順序に依存する必要はありません。親列は、テーブルのメインID列を参照します。

は、基本的には(2つのテーブルにこれを分割することができるかもしれ私に示唆)行の2種類があります。

  • 演算子を持つ行が1つのまたは複数の条件を組み合わせた「ノード」であります/ノードの2つの論理演算子のいずれかを使用して(しかし、私はあなたが任意の論理演算子を使用することができると思います)。これらのノードにはcondition_idがありません。
  • condition_idが1つの条件を表す行(私はあなたの例に従って番号を付けました)。これらの行には演算子がありません。これは、1つのオペランドに演算子を含めることができないためです。あなたの基本条件が、自分の質問の詳細を抽象化したのと同じ論理演算子を使用するかどうかは考慮していません。

私はあなたにもrule_idが必要かどうか分かりません。この例では、各ルール(名前/ラベル、有効な日付範囲など)に関するメタ情報を保存する場合は、別のテーブルにそのルールを抽出することをおすすめします。また、MySQLが再帰的クエリAFAIAAを簡単に処理できないため、PHPでロジックを再構築するのが簡単になるかもしれません。

+0

美しい。私はこれをかなり分析し、私はそれを愛しています。今日と明日に行って、それがどのように機能するかを報告します。ありがとう! – Swader

+0

@Swaderこれで運がいい? – liquorvicar

+0

まだロジックを構築していて、いくつかの新機能が追加されました。これをコンポーネントとしてデカップリングするので、他のフレームワークでも使用できます。もし私が呼吸をキャッチしたら、二日で完了し、テストしなければならない。 – Swader

1

ID | Rule_ID | Condition_ID | Level | Operator | 
------------------------------------------------------------ 
1 | 1   | 1    | 0  | AND  | 
2 | 1   | 2    | 1  | OR  | 
3 | 1   | 1    | 1  | OR  | 
4 | 1   | 2    | 0  | NULL  | 

だから、それが生成します:

条件1 & &を(条件2 ||条件1)||条件2

OK]をクリックして、ここで私が成功したものです:

<?php 

/*(condition1) && 
(condition2) && 
    (condition3 
    || condition4 
    || 
     (condition6 && 
     condition7) 
    ) && 
(condition5) 

id | RuleID | conditionID | level | operator 
------------------------------------------------- 
1  1   1    1   AND 
2  1   2    1   AND 
3  1   3    2   OR 
4  1   4    2   OR 
5  1   6    3   AND 
6  1   7    3   AND 
7  1   5    1   NULL 

*/ 

$conditions = array(
    array(), 
    array(condition=>"condition1"), 
    array(condition=>"condition2"), 
    array(condition=>"condition3"), 
    array(condition=>"condition4"), 
    array(condition=>"condition5"), 
    array(condition=>"condition6"), 
    array(condition=>"condition7") 
); 

$rules = array(
    array(RuleID=>1,conditionID=>1,level=>1,operator=>"AND"), 
    array(RuleID=>1,conditionID=>2,level=>1,operator=>"AND"), 
    array(RuleID=>1,conditionID=>3,level=>2,operator=>"OR"), 
    array(RuleID=>1,conditionID=>4,level=>2,operator=>"OR"), 
    array(RuleID=>1,conditionID=>6,level=>3,operator=>"AND"), 
    array(RuleID=>1,conditionID=>7,level=>3,operator=>"AND"), 
    array(RuleID=>1,conditionID=>5,level=>1,operator=>null) 
); 

echo "<pre>"; 
//print_r($conditions); 
//print_r($rules); 


//mocking mysql ruleID filter with array_filter() 
$firstrule = array_filter($rules,function($element){return ($element["RuleID"]==1);}); 

var_dump($firstrule); 

$level = 1; 
$condition_count = count($firstrule); 
foreach($firstrule as $key=>$condition){ 

    $new_level = $condition["level"]; 
    $next_level = $firstrule[$key+1]["level"]; 
    $prev_op = $firstrule[$key-1]["operator"]; 

    if($new_level!=$level){ 
     if($new_level>$level){ 
      echo str_repeat("(",$new_level-$level); 
      if($condition_count > $key && $next_level < $new_level){ 
       echo $conditions[$condition["conditionID"]]["condition"]; 
      }else{ 
       echo $conditions[$condition["conditionID"]]["condition"].getOperator($condition["operator"]); 
      } 
     } 
     else 
     { 
      if($condition_count > $key && $next_level < $new_level){ 
       echo str_repeat(")",$level-$new_level); 
       echo getOperator($prev_op).$conditions[$condition["conditionID"]]["condition"] ; 
      }else{ 
       echo str_repeat(")",$level-$new_level); 
       echo $conditions[$condition["conditionID"]]["condition"] ; 
      } 
     } 
    }else{ 
     if($condition_count > $key && $next_level < $new_level){   
      echo $conditions[$condition["conditionID"]]["condition"]; 
     }else{  
      echo $conditions[$condition["conditionID"]]["condition"].getOperator($condition["operator"]); 
     } 

    } 
    $level = $new_level; 
} 

function getOperator($op){ 
    switch($op){ 
     case "AND": return "&&"; 
     case "OR" : return "||"; 
     case null : return ""; 
     default : return ""; 
    } 
} 

?> 
+0

いい考えですが、この構造で私の例をどのように構築するのか分かりません。あなたはどうかデモンストレーションできますか? – Swader

+0

OK待ち。私が試してみます。 –

+0

このコードの出力は、 '条件1 &&条件2 &&(条件3 ||条件4 ||(条件6 &&条件7))&&条件5' –

関連する問題