データベース内の表形式または複数のドキュメントフィールドの変更

多くの場合、プロジェクトでは、ドキュメントの複数のフィールドをデータベースで更新する必要があります。 おそらく既製のソリューションがありますが、Googleに「ドキュメントの複数のプロパティを変更する」、「複数のフィールドを処理する」、「テーブルフィールドを処理する」などの理由で解決策が見つからなかったので、独自の記事を書いて同時にこの記事で説明することにしました。





すべての例はPHPにあり、mysqlデータベースが使用されます。 上記のコードはどのデータベースにも関連付けられていませんが、削除する行、追加する行、変更する行を決定するだけです。 さらに、これらの「命令」は、任意のデータベースに簡単に実装できます。



たとえば、「識別子」、「名前」、「作成日」などの単一のプロパティを持つ単純なドキュメントがあり、このドキュメントには複数のフィールドがあります-フォーム内のアクセス制御テーブル:ユーザーコード、アクセス許可の開始日時、アクセスが拒否された日時。



PHPの特定のドキュメントのデータ構造は、次のように表すことができます。

$document["id"] = "1"; //   $document["name"] = " "; //   $document["create_date"] = "25-10-2012"; //    $document["permissions_table"] = array( array( "user_id" => 1, //   "grant_from" => "2012-10-25 00:00:00", //        "grant_to" => "2012-10-27 23:59:59" //        ) );
      
      







データベースでは、そのようなドキュメントは2つのテーブルに格納されると想定しています。

 /* - document_header (   ,   -  ) id INT NOT NULL AUTOINCREMENT name TEXT NOT NULL create_date DATETIME NOT NULL - document_permissions (   ,   -  ) id INT NOT NULL AUTOINCREMENT document_id INT NOT NULL user_id INT NOT NULL grant_from DATETIME grant_to DATETIME */
      
      







次に、ドキュメントのアクセステーブルを変更するタスクが発生することを想像してください。 さらに、ユーザーが送信した後、処理用のドキュメントの2つの配列を取得します。古いデータの配列と新しいデータの配列です。



次に、これらの配列をSQLクエリのシーケンスに変換して、データベース内のドキュメントを変更する方法を見てみましょう。



フラットデータでは、すべてが非常に単純で、次のコードで処理できます

 $changes = array(); foreach($old_document as $k => $v) { if($k == "permissions_table") continue; if($old_document[$k] != $new_document[$k]) $changes[$k] = $new_document[$k]; } $changes["id"] = $old_document["id"] $changes["document_id"] = $old_document["document_id"]
      
      







その結果、変更されたフィールドとその新しい値を含む$変更の配列を取得します。これは、UPDATEデータベースクエリに簡単に変換できます。 この操作で記事をオーバーロードしたくないので、省略します。



次に、ドキュメントアクセステーブルの変更を処理し、データベースに必要な変更を加える必要があります。

ここでは、さまざまな状況が発生する可能性があります。例えば:

-古い行が変更されました

-新しい行が追加されました

-古い行が削除されました

-行の順序が変更されました



上記の操作の任意の組み合わせ。



この場合、データベースに適切なクエリを生成し、必ず次の順序で実行する必要があります。

1.余分な行を削除する

2.既存の行を変更する

3.新しい行を追加する

削除は、主に追加または変更操作中にデータベース内の一意のキーの競合がないように実行されます。



その結果、入力で古い値と新しい値の配列を受け取る関数が必要になり、出力では、削除、変更、およびデータベースへの追加が必要なテーブル行を含む3つの配列を提供します。



このタスクのために、表データの任意の構成で機能するユニバーサル関数を作成しました。 記事の最後に示されているいくつかの制限がある場合のみ。



そのため、マジック関数には次のインターフェースがあります。

 /* @$data -      @$old_data -      @$keys -       (, .      ) @$hidden_keys -     ,     (.      ) @$options -   */
      
      





出力では、大切な配列の削除、更新、挿入を取得します。これらは、後続の実行のためにデータベースクエリに簡単に変換できます。



関数のソースコード:

 static function generateOperationsFromMultiData($data, $old_data, $keys, $hidden_keys, $options) { $out = array("insert" => array(), "update" => array(), "delete" => array()); $unique_elements = array(); $unique_keys = array(); //           $old_elements_hashes = array(); $old_elements_keys = array(); foreach($old_data as $k => $fields) { $res = self::__getKeyAndHashFromLine($fields, $keys, $hidden_keys); $old_data[$k]["___key"] = $res["key"]; $old_data[$k]["___hash"] = $res["hash"]; if($res["key"]) { $old_elements_hashes[$res["key"]] = $res["hash"]; $old_elements_keys[$res["key"]] = $k; } else { $old_elements_hashes[$k] = $res["hash"]; } } //     $data = array_merge($data); foreach($data as $k => $fields) { $res = self::__getKeyAndHashFromLine($fields, $keys); $data[$k]["___key"] = $res["key"]; $data[$k]["___hash"] = $res["hash"]; foreach($hidden_keys as $k2) unset($fields[$k2]); //        if($options["unique"]) { if(in_array($res["hash"], $unique_elements)) continue; else $unique_elements[] = $res["hash"]; } if($res["key"]) { //         if(in_array($res["key"], $unique_keys)) continue; else $unique_keys[] = $res["key"]; //          if(!isset($old_elements_hashes[$res["key"]])) $out["insert"][$k] = $fields; else { //      ,    if($res["hash"] != $old_elements_hashes[$res["key"]]) { //         foreach($hidden_keys as $v) { $fields[$v] = $old_data[$old_elements_keys[$res["key"]]][$v]; } //        $out["update"][$k] = $fields; } $old_data[$old_elements_keys[$res["key"]]]["___new_key"] = $k; unset($old_elements_hashes[$res["key"]]); unset($old_elements_keys[$res["key"]]); } } else { //            if($key = array_keys($old_elements_hashes, $res["hash"])) { $key = current($key); unset($old_elements_hashes[$key]); $old_data[$key]["___new_key"] = $k; } else { //    ,    $out["insert"][$k] = $fields; } } } //   old_data      if($keys) foreach($old_elements_keys as $k => $v) { unset($old_data[$v]["___key"]); unset($old_data[$v]["___hash"]); unset($old_data[$v]["___new_key"]); $out["delete"][] = $old_data[$v]; unset($old_data[$v]); } else foreach($old_elements_hashes as $k => $v) { unset($old_data[$k]["___key"]); unset($old_data[$k]["___hash"]); unset($old_data[$k]["___new_key"]); $out["delete"][] = $old_data[$k]; unset($old_data[$k]); } //      //    $old_data = array_merge($old_data); $data = array_merge($data); if($options["save_order"]) { $delete = false; //    (  ,           update ) if($old_data[0]["___new_key"] != "0") $delete = true; foreach($old_data as $k => $v) { //    ,        if($v["___new_key"] != $k) $delete = true; if($delete) { unset($old_data[$k]["___key"]); unset($old_data[$k]["___hash"]); unset($old_data[$k]["___new_key"]); unset($data[$v["___new_key"]]["___key"]); unset($data[$v["___new_key"]]["___hash"]); $out["delete"][] = $old_data[$k]; foreach($hidden_keys as $hk) { $data[$v["___new_key"]][$hk] = $old_data[$k][$hk]; } $out["insert"][$v["___new_key"]] = $data[$v["___new_key"]]; if($keys) unset($out["update"][$v["___new_key"]]); } } } $out["update"] = array_merge($out["update"]); ksort($out["insert"]); $out["insert"] = array_merge($out["insert"]); return $out; } //     function __getKeyAndHashFromLine($line, $keys, $hide_keys = array()) { $hash = $line; //   foreach($keys as $v) unset($hash[$v]); foreach($hide_keys as $v) unset($hash[$v]); //    $hash = serialize($hash); //   $key = ""; foreach($keys as $v) $key .= "__" . $line[$v]; return array("hash" => $hash, "key" => $key); }
      
      







この場合、関数呼び出しは次のようになります。

 $result = generateOperationsFromMultiData($new_document["permissions_table"], $old_document["permissions_table"], false, array("id"), array("unique" => false));
      
      





その結果、 $ resultには、 deleteupdateinsertの 3つの配列が含まれます。



説明のためにいくつかの例を示します。

最初の例では、2人のユーザー用の2行があります。 変更をエミュレートして、3番目のユーザーを紹介し、2番目のユーザーを削除します。 同時に、特別に最初のユーザーの行を複製し、両方の行の日付を変更します。

 $old_document["permissions_table"] = array( array( "id" => 1, "document_id" => 1, "user_id" => 1, "grant_from" => "2012-10-25 00:00:00", "grant_to" => "2012-10-27 00:00:00" ), array( "id" => 2, "document_id" => 1, "user_id" => 2, "grant_from" => "2012-10-25 00:00:00", "grant_to" => "2012-10-27 00:00:00" ) ); $new_document["permissions_table"] = array( array( "document_id" => 1, "user_id" => 3, "grant_from" => "2012-10-25 00:00:00", "grant_to" => "2012-10-27 00:00:00" ), array( "document_id" => 1, "user_id" => 1, "grant_from" => "2012-10-25 00:00:00", "grant_to" => "2012-10-03 00:00:00" ), array( "document_id" => 1, "user_id" => 1, "grant_from" => "2012-10-25 00:00:00", "grant_to" => "2012-10-31 00:00:00" ) ); generateOperationsFromMultiData( $new_document["permissions_table"], $old_document["permissions_table"], array("user_id"), array("id"), array( "unique" => false, "save_order" => false ) )
      
      





出力では次のようになります

 Array ( [insert] => Array ( [0] => Array ( [document_id] => 1 [user_id] => 3 [grant_from] => 2012-10-25 00:00:00 [grant_to] => 2012-10-27 00:00:00 ) ) [update] => Array ( [0] => Array ( [document_id] => 1 [user_id] => 1 [grant_from] => 2012-10-25 00:00:00 [grant_to] => 2012-10-03 00:00:00 [id] => 1 ) ) [delete] => Array ( [0] => Array ( [id] => 2 [document_id] => 1 [user_id] => 2 [grant_from] => 2012-10-25 00:00:00 [grant_to] => 2012-10-27 00:00:00 ) ) )
      
      





その結果、3番目のユーザーで行を挿入し、2番目のユーザーで行を削除し、最初のユーザーで変更を加える必要があることがわかりました。 最初のユーザーの変更は、 $ new_document [permissions_table]配列のこのユーザーの最初の行から取得されることに注意してください。 これにより、「複製されたデータ」の正しい処理を示したかったのです。



次に、関数の動作を制御するパラメーターを検討します。



$ keys-テーブルデータキーの配列。 指定すると、関数は自動的に重複キーを持つ行をスローし始めます。上記の例では、キーは「user_id」であるため、同じユーザーの行の繰り返しを禁止しています。 キーはコンポジットにすることができます。このため、このパラメーターの配列でキーを指定するだけで十分です。 キーを指定しない場合、関数は引き続き機能しますが、データベースに何らかのIDを入力する必要があります。そのため、ある行を別の行と区別する必要があります。 $ hidden_​​keys関数に登録する必要があります。



$ hidden_​​keys-非表示キー。これらは、変更されたデータの配列ではなく、古いデータの配列に存在する可能性があるキーです。 この場合、関数はこれらのキーを行の削除および変更の出力配列に自動的に転送します。 特に、行が1つ以上の非キーフィールドで構成されている場合、複数のデータを管理するために必要です。 次に、そのような行を識別するために、一意のIDがデータベースに入力されますが、編集中にフォームに「ドラッグ」してその「安全性」を監視する必要はありません。 関数自体は、削除する特定のIDを持つ行、変更する行、および追加する行を決定します。



$ options [unique] -このフラグをtrueに設定すると、キーの一意性に加えて、関数は残りの文字列データの一意性のチェックを開始します。つまり、 $ options [unique]フラグを設定すると、異なる期間に同じ期間を指定できなくなりますユーザー。この場合、関数は最初の利用可能な期間を残し、後続の繰り返し期間を削除します。



$ options [save_order] -データベース内のデータの順序を保持する必要があることを示すフラグ。 $ data配列と同じです(この例では、 $ new_document [permissions_table] )。 このフラグがどのように機能するかを理解するために、 $ options [save_order]フラグが設定されている場合のみ、この例の結果を検討してください。

 Array ( [insert] => Array ( [0] => Array ( [document_id] => 1 [user_id] => 3 [grant_from] => 2012-10-25 00:00:00 [grant_to] => 2012-10-03 00:00:00 ) [1] => Array ( [document_id] => 1 [user_id] => 1 [grant_from] => 2012-10-25 00:00:00 [grant_to] => 2012-10-03 00:00:00 [id] => 1 ) ) [update] => Array ( ) [delete] => Array ( [0] => Array ( [id] => 2 [document_id] => 1 [user_id] => 2 [grant_from] => 2012-10-25 00:00:00 [grant_to] => 2012-10-27 00:00:00 ) [1] => Array ( [id] => 1 [document_id] => 1 [user_id] => 1 [grant_from] => 2012-10-25 00:00:00 [grant_to] => 2012-10-27 00:00:00 ) ) )
      
      





最初に、この関数は、3番目のユーザーで新しいレコードを挿入し、その後に最初のユーザーでレコードを挿入するために、既存のレコードをすべて削除することを提案していることがわかります。 したがって、データベースでは、新しい配列のように、ソートせずにフェッチするときに同じシーケンスを取得します。 この機能を使用すると、行のソートに必要な追加フィールドを保存できます。 ただし、行がテーブルの中央または先頭に挿入される場合、最初にこの行に続くすべてのデータを削除し、次にそれらを再度追加する必要があります(これらのアクションは最後の例で見ました)



注:目的の結果を得るために関数は常に最小数のデータベースクエリを提供します。



制限:行データは、関数の実行時にのみフラットにする必要があります。 フィールドは「___ key」、「___ hash」、「___ new_key」と呼ばないでください。




All Articles