挑戦する
ええ、あなたはボートに乗って水に乗って人生を楽しみます。 私は休息するために次の湖に行きました、そして彼らは犬やボートは許可されていないと言っているとあなたに話します、そして一般的に私たちの湖はいつも凍っています、ここであなたはスケートを持っています-お楽しみください。 「仮想ホスティング湖へようこそ。」 どういうわけか、 スーパーユーザーのみがMySQLでトリガーを作成できるという事実に注意を払っていませんでしたが、これはやや驚くべきことですが、開発者の良心に任せましょう。 基本的にPerlのソリューションはありますが、作成した時点では完全に異なるタスクと要件がありました。 したがって、この記事は以前の開発をキャンセルするのではなく、追加のソリューションを提供するだけです。 データベースを操作するための特定のオブジェクトセットと特定の「ラッパー」があります。 この「ラッパー」には、このモジュールを機能の拡張として含めます。 ラッパーは自己記述型です。 DBIx :: Classやその他の既成のソリューションの反対者ではないので、事前に予約します。仕事でそれらを使用して満足しています。 質問は仮想ホスティングとそれに似た他のものにかかっています:mod_perlの欠如と追加モジュールのインストールのhemo。 同じDBIx :: Classのソリューションは開発中ですが、必要がないのであまり高速ではないので、十分なトリガーがあるため、 挿入 、 更新 、 削除の 3つの手順だけが必要です。 これはプロシージャであり、「ラッパー」のオブジェクトのメソッドとして継承されます。 ただし、この記事では、ほぼ自給自足にします。 このモジュールにはトランザクションを含めませんでした。1レベル上で使用しているため、自分でコードに含めることは難しくないと思います。 、機能の少しのテストが実行されましたが。
基本的な手順と変数
もちろん、データベースに接続するための手順ですが、外部から定義されているパッケージ$ dbhのオブジェクトがあります。 また、普遍性を確保するために、ツリーの構造を担当する独自のフィールドセットを各テーブルに定義する配列を作成します。
Perlコード(1)
パッケージMY :: NestedSets; #妥協のない大人としてのすべて;-) 厳格な使用; 警告を使用します。 $ VERSION = '0.0.1'; #パッケージ内で使用する変数を定義します $ dbh = undef; $テーブル= { デフォルト=> {#テーブル名 フィールド=> {#テーブルフィールド id => 'id'、#実際にID、だれもがどのように電話するかわかりません left_key => 'left_key'、#左キー right_key => 'right_key'、#右キー level => 'level'、#レベル parent_id => 'parent_id'、#親ID tree => 'tree'#ツリー識別子 }、 multi => 1、#テーブルに複数のツリーがあることを示します }、 }; sub dbh { #まだ作成している場合、最初の値はパッケージの名前またはパッケージのクラスになります #それで、私たちは時々それを断ち切り、クラスを持っていません。 shift if $ _ [0] &&($ _ [0] eq __PACKAGE__ ||(ref $ _ [0] && ref $ _ [0] eq __PACKAGE__)); $ dbh = $ _ [0] if $ _ [0]; return $ dbh; } sub set_table_params { shift if $ _ [0] &&($ _ [0] eq __PACKAGE__ ||(ref $ _ [0] && ref $ _ [0] eq __PACKAGE__)); #特定のテーブルのフィールドを設定する my($ table_name、$ params)= @_; $ tables-> {$ table_name} = $ params; $テーブルを返します。 }
並行して、useスクリプト自体を記述しますが、これもテスト用です。 そのため、モジュールを使用して、そのメインデータを決定します。
Perlコード(2)
#!/ usr / bin / perl 厳格な使用; 警告を使用します。 lib '../lib'を使用します。 MY :: NestedSetsを使用します。 DBIを使用します。 Data :: Dumperを使用します。 #------------------------------------------------- -------------------------------------------------- ----- #INIT my $ dbh = DBI-> connect( 'dbi:mysql:database = test; host = localhost; port = 3306'、 'user'、 'pass'); 私の$ table_name = 'test_nested_sets'; my%f =( id => 'ids'、 left_key => 'lk'、 right_key => 'rk'、 レベル=> 'lv'、 parent_id => 'pi'、 ツリー=> 'tr'、 ); $ dbh-> do( "DROP TABLE` $ table_name`;"); my $ query = "CREATE TABLE` $ table_name`( `$ f {id}` int(11)NOT NULL auto_increment、 `$ f {left_key}` int(11)NOT NULLデフォルト '0'、 `$ f {right_key}` int(11)NOT NULLデフォルト '0'、 `$ f {level}` int(11)NOT NULLデフォルト '0'、 `$ f {parent_id}` int(11)NOT NULLデフォルト '0'、 `$ f {tree}` int(11)NOT NULLデフォルト '1'、 `field1` VARCHAR(100)、 主キー( `$ f {id}`) )エンジン= MyISAM; "; $ dbh-> do($ query); MY :: NestedSets-> dbh($ dbh); MY :: NestedSets-> set_table_params($ table_name => {fields => \%f、multi => 1}); ...
ノードを挿入
作業のロジックは、トリガーのロジックと同じです。
Perlコード(3)
サブ挿入{ #着信データを適切に場所に配布し、それに応じて十分なデータがあるかどうかを確認します shift if $ _ [0] &&($ _ [0] eq __PACKAGE__ ||(ref $ _ [0] && ref $ _ [0] eq __PACKAGE__)); my($ table_name、$ new)= @_; return {success => 0、error => 'Bad Income data!'} $ dbh && $ table_name && $ new && ref $ new && ref $ new eq 'HASH'; #どんな種類のテーブルを見つけて、追加の属性とフィールドシノニムを取得します 私の$ table = $ tables-> {$ table_name} || $ tables-> {default}; 私の$ f = $ table-> {fields}; 私の$ result_flags = {is_last_unit => undef}; #ツリーキーの初期データを決定する $ new-> {$ f-> {left_key}} || = 0; $ new-> {$ f-> {right_key}} = undef; $ new-> {$ f-> {level}} = undef; $ new-> {$ f-> {parent_id}} || = 0; #親ノードを指定または変更した場合、キーを決定します if($ new-> {$ f-> {parent_id}}){ 私の$ sql = 'SELECT'。 ($テーブル-> {multi}?$ f-> {tree}。「ASツリー」: '')。 $ f-> {right_key}。 ' AS left_key、 '。 $ f-> {レベル}。 ' + 1 ASレベル '。 「FROM」$ Table_name。 'WHERE'。$ F-> {id}。 ' = '。$ new-> {$ f-> {parent_id}}; #明確にするために、これはクエリです(角括弧はオプションの式です): #SELECT [tree AS tree、] right_key AS left_key、level + 1 AS level FROM $ table_name WHERE id = $ parent_id; 私の$ sth = $ dbh-> prepare($ sql); $ sth->実行|| return {success => 0、error => $ dbh-> errstr}; 私の$ row = $ sth-> fetchrow_hashref(); $ sth-> finish; #親ノードが見つかったため、キー値を再定義します if($ row){ $ new-> {$ f-> {tree}} = $ row-> {tree} || 未定義 $ new-> {$ f-> {left_key}} = $ row-> {left_key}; $ new-> {$ f-> {level}} = $ row-> {level}; } else { #親ノードが見つからないため、parent_idが残っているため、リセットします $ new-> {$ f-> {parent_id}} = 0; $ new-> {$ f-> {level}} = 0; } } #左キーが指定されている場合、キーを決定しますが、同時に、親ノードが指定されていないか、見つかりません if(!$ new-> {$ f-> {parent_id}} && $ new-> {$ f-> {left_key}}){ #これは重要です! マルチツリーの場合、$ treeパラメーターが必要です $ new-> {$ f-> {tree}} && $ table-> {multi};でない限り、{success => 0、error => 'No tree value!'} #最初はSQLを使用したかった::抽象的だが、気に入らなかった。複雑なクエリを記述するのは難しくて長い #左右のキーでノードを見つける 私の$ sql = 'SELECT'。 $ f-> {id}。 ' AS id、 '。 $ f-> {left_key}。 ' AS left_key、 '。 $ f-> {right_key}。 ' AS right_key、 '。 $ f-> {レベル}。 ' ASレベル、 '。 $ f-> {parent_id}。 ' AS parent_id '。 「FROM」$ Table_name。 「どこ」。 ($テーブル-> {multi}?$ f-> {tree}。 '='。$ new-> {$ f-> {tree}}。 'AND': '')。 '('。$ f-> {left_key}。 '='。$ new-> {$ f-> {left_key}}。 'OR'。 $ f-> {right_key}。 ' = '。$ new-> {$ f-> {left_key}}。')LIMIT 1 '; #読み取り可能なリクエスト: #選択 #id AS id、 #left_key AS left_key、 #right_key AS right_key、 #レベルASレベル、 #parent_id AS parent_id #FROM $ table_name #どこ #[tree = $ tree AND] #(left_key = $ left_keyまたはright_key = $ left_key) #LIMIT 1; 私の$ sth = $ dbh-> prepare($ sql); $ sth->実行|| return {success => 0、error => $ dbh-> errstr}; 私の$ row = $ sth-> fetchrow_hashref(); $ sth-> finish; #左キーでノードが見つかったため、見つかった新しいノード if($ row && $ row-> {left_key} == $ new-> {$ f-> {left_key}}){ $ new-> {$ f-> {parent_id}} = $ row-> {parent_id}; $ new-> {$ f-> {level}} = $ row-> {level}; #ノードは正しいキーで検出されたため、新しいノードは検出されたノードの下にあります } elsif($行){ $ new-> {$ f-> {parent_id}} = $ row-> {id}; $ new-> {$ f-> {level}} = $ row-> {level} + 1; } else { #繰り返しますが、そのようながらくたは、完全に残ったデータを示しています。 誓うのは良いことですが、今のところ、これらの群れを無視してください。 #このデータがなくても処理できるため $ new-> {$ f-> {left_key}} = undef; } } #実際に、挿入ポイントを取得できなかったか、単に示されていませんでした。 #ツリーの最後に挿入するため、既存のノードを更新する必要はありません。したがって、対応するフラグを作成します。 ($ new-> {$ f-> {left_key}}){ $ result_flags-> {is_last_unit} = 1; #これもまた重要です! 複数ツリーの場合は、$ treeパラメーターが必要です。 #一般に、最初にこれを確認できますが、parent_idを指定した場合、このパラメーターは不要です。 #次に、ツリーキーの値が決定されます。 $ new-> {$ f-> {tree}} && $ table-> {multi};でない限り、{success => 0、error => 'No tree value!'} #それは簡単です、最大の正しいキーを決定して喜ぶ 私の$ sql = 'SELECT MAX('。$ f-> {right_key}。 ')+ 1 AS left_key FROM '。$ Table_name。 ($ table-> {multi}? 'WHERE'。$ f-> {tree}。 '='。$ new-> {$ f-> {tree}}: ''); #読み取り可能なリクエスト: #SELECT MAX(right_key)+ 1 AS left_key、 #FROM $ table_name #[WHERE tree = $ tree]; 私の$ sth = $ dbh-> prepare($ sql); $ sth->実行|| return {success => 0、error => $ dbh-> errstr}; 私の$ row = $ sth-> fetchrow_hashref(); $ sth-> finish; #しかし、ノードがまったくない可能性があるため、喜びは完全ではない可能性があります $ new-> {$ f-> {left_key}} = $ row-> {left_key} || 1; $ new-> {$ f-> {parent_id}} = 0; $ new-> {$ f-> {level}} = 0; } #さて、場所で、ツリーのキーを壊すことができると決めました: ($ result_flags-> {is_last_unit}){ my $ query = 'UPDATE'。$ table_name。 'SET'。$ F-> {left_key}。 ' =ケース '。$ F-> {left_key}の場合。 > = '。$ new-> {$ f-> {left_key}}。 それから '。$ F-> {left_key}'。 + 2 ELSE '。$ F-> {left_key}'。 END、 '。$ f-> {right_key}'。 = '。$ f-> {right_key}。' + 2 WHERE '。 ($テーブル-> {multi}?$ f-> {tree}。 '='。$ new-> {$ f-> {tree}}。 'AND': '')。 $ f-> {right_key}。 ' > = '。$ new-> {$ f-> {left_key}}; #読み取り可能なリクエスト: #UPDATE $ table_name #セット #left_key = left_key> = $ left_keyの場合 #THEN left_key + 2 #ELSE left_key #END、 #right_key = right_key + 2 #WHERE [tree = $ tree AND] right_key> = $ left_key; $ dbh-> do($ query)|| return {success => 0、error => $ dbh-> errstr}; } #実際、なぜここに来たのか: #正しいキーが計算されます $ new-> {$ f-> {right_key}} = $ new-> {$ f-> {left_key}} + 1; #キーを置きます $ new-> {$ f-> {tree}} = $ new-> {$ f-> {tree}} if if table-> {multi}; #フィールドを特定の順序で表示する必要がある 私の@fields = keys%{$ new}; #ここで、非数値の空の行を引用して@fieldsの順に詰めるには #そしてはい、少なくとも二重引用符については、ここに来る前にチェックする必要があります 私の@values = map {defined $ new-> {$ _} && $ new-> {$ _} =〜/ ^ \ d + $ /? $ new-> {$ _}: '"'。$ new-> {$ _}。 '"'} @fields; #実際に挿入 my $ query = 'INSERT INTO'。$ table_name。 ' ( '。(join'、 '、@fields)')VALUES( '。(join'、 '、@values)。') '; $ dbh-> do($ query)|| return {success => 0、error => $ dbh-> errstr}; #しかし、返すべきものは別の質問です。残念ながら、フェッチせずに挿入された行を返すことはできません。 #テーブルにはデフォルトのフィールド値がありますが、INSERTでそれらを指定しなかったため。 #同じSELECTをしましょう 私の$ sql = 'SELECT * FROM'。$ table_name。 ' ORDER BY '。$ F-> {id}。' DESC LIMIT 1 '; 私の$ sth = $ dbh-> prepare($ sql); $ sth->実行|| return {success => 0、error => $ dbh-> errstr}; 私の$ row = $ sth-> fetchrow_hashref; $ sth-> finish; return {success => 1、row => $ row}; }
はい、たくさんのコードが判明しました...しかし、コメントを削除すると、行数が半分になります;-)が、はっきりしていると思います。 基本的に:繰り返しますが、親の設定が優先されます。 親が指定され、左のキーが指定されている場合、有効なツリーでは後者が無視されます。 したがって、何かに従属するノードを作成すると同時に、子のリスト内でその場所を指定する場合は、parent_idを渡す必要がないことに注意してください。
Perlコード(4)
...私の$ツリー= 1; #------------------------------------------------- -------------------------------------------------- --------------------#INSERT#座標なしで記録my $ insert = MY :: NestedSets-> insert($ table_name、{field1 => 'row1-'。 $ tree、tr => $ tree}); Dumper $ insertに警告します。 #親のあるレコード$ insert = MY :: NestedSets-> insert($ table_name、{field1 => 'row2-'。$ Tree、pi => $ insert-> {row}-> {ids}、tr => $ツリー}); Dumper $ insertに警告します。 #left_keyのエントリ$ insert = MY :: NestedSets-> insert($ table_name、{field1 => 'row3-'。$ Tree、lk => 1、tr => $ tree}); Dumper $ insertに警告します。 $ insert = MY :: NestedSets-> insert($ table_name、{field1 => 'row4-'。$ tree、lk => 4、tr => $ tree}); Dumper $ insertに警告します。 #間違ったパラメーター$ insert = MY :: NestedSets-> insert($ table_name、{field1 => 'row5-'。$ Tree、pi => 1000、tr => $ tree}); Dumper $ insertに警告します。 $ insert = MY :: NestedSets-> insert($ table_name、{field1 => 'row6-'。$ tree、lk => 100、tr => $ tree}); Dumper $ insertに警告します。 ...
ノード変更
ツリー構造を(必要に応じて)直接変更することに加えて、変更は必要に応じて他のフィールドにも適用されます。
Perlコード(5)
サブアップデート{ #受信データを場所に配布し、それに応じて、十分なデータがあるかどうかを確認します シフトif $ _ [0] &&($ _ [0] eq __PACKAGE__ ||(ref $ _ [0] && ref $ _ [0] eq __PACKAGE__)); my($ table_name、$ new)= @_; return {success => 0、error => 'Bad Income data!'} $ dbh && $ table_name && $ new && ref $ new && ref $ new eq 'HASH'; #どんな種類のテーブルを見つけて、追加の属性とフィールドシノニムを取得します 私の$ table = $ tables-> {$ table_name} || $ tables-> {default}; 私の$ f = $ table-> {fields}; リターン{成功=> 0、エラー=> '悪い収入データ!'} $ new-> {$ f-> {id}}; #個別に変更できないフィールドは削除します 削除$ new-> {$ f-> {right_key}}; 削除$ new-> {$ f-> {tree}}; 削除$ new-> {$ f-> {level}}; 私の$ tmp_left_key = $ new-> {$ f-> {left_key}}; 私の$ result_flags = {it_is_moving => undef}; #さらにジレンマ。 変更を受け入れるには、ソースデータが必要です #この場合、どの初期データがあり、どのフィールドが実際に変更されたかはわかりませんが、 #可変ノードをサンプリングする 私の$ sql = 'SELECT * FROM'。$ table_name。 ' WHERE '。$ F-> {id}。' = '。$ new-> {$ f-> {id}}; 私の$ sth = $ dbh-> prepare($ sql); $ sth->実行|| return {success => 0、error => $ dbh-> errstr}; $ old = $ sth-> fetchrow_hashref; $ sth-> finish; return {success => 0、error => 'No old unit!'}が$ oldでない限り; #新しいノード座標を計算する #親ノードを変更した場合、キーを決定します if(定義済み$ new-> {$ f-> {parent_id}} && $ new-> {$ f-> {parent_id}}!= $ old-> {$ f-> {parent_id}}){ if($ new-> {$ f-> {parent_id}}> 0){ 私の$ sql = 'SELECT'。 ($テーブル-> {multi}?$ f-> {tree}。「ASツリー」: '')。 $ f-> {right_key}。 ' AS left_key、 '。 $ f-> {レベル}。 ' + 1 ASレベル '。 「FROM」$ Table_name。 'WHERE'。$ F-> {id}。 ' = '。$ new-> {$ f-> {parent_id}}; #明確にするために、これはクエリです(角括弧はオプションの式です): #SELECT [tree AS tree、] right_key AS left_key、level + 1 AS level FROM $ table_name WHERE id = $ parent_id; 私の$ sth = $ dbh-> prepare($ sql); $ sth->実行|| return {success => 0、error => $ dbh-> errstr}; 私の$ row = $ sth-> fetchrow_hashref(); $ sth-> finish; #親ノードが見つかった後、キー値を再定義します if($ row){ $ new-> {$ f-> {tree}} = $ row-> {tree} if if table-> {multi}; $ new-> {$ f-> {left_key}} = $ row-> {left_key}; $ new-> {$ f-> {level}} = $ row-> {level}; $ result_flags-> {it_is_moving} = 1; } else { #親ノードが見つからないため、parent_idが残っているため、リセットします $ new-> {$ f-> {parent_id}} = $ old-> {$ f-> {parent_id}}; } } else { #最高レベルに移行 #それは簡単です、最大の正しいキーを決定して喜ぶ 私の$ sql = 'SELECT MAX('。$ f-> {right_key}。 ')+ 1 AS left_key FROM '。$ Table_name。 ($ table-> {multi}? 'WHERE'。$ f-> {tree}。 '='。$ old-> {$ f-> {tree}}: ''); #読み取り可能なリクエスト: #SELECT MAX(right_key)+ 1 AS left_key、 #FROM $ table_name #[WHERE tree = $ tree]; 私の$ sth = $ dbh-> prepare($ sql); $ sth->実行|| return {success => 0、error => $ dbh-> errstr}; 私の$ row = $ sth-> fetchrow_hashref(); $ sth-> finish; $ new-> {$ f-> {left_key}} = $ row-> {left_key}; $ new-> {$ f-> {parent_id}} = 0; $ new-> {$ f-> {level}} = 0; } } #左キーが設定されているが、親ノードが指定されていないか見つからない場合、キーを決定します if($ tmp_left_key && $ new-> {$ f-> {left_key}} &&#left_keyが指定された $ new-> {$ f-> {left_key}} == $ tmp_left_key &&#parent_idは変更されていません $ tmp_left_key!= $ old-> {$ f-> {left_key}}){#left_key changed #最初はSQLを使用したかった::抽象的だが、気に入らなかった。複雑なクエリを記述するのは難しくて長い #左右のキーでノードを見つける 私の$ sql = 'SELECT'。 $ f-> {id}。 ' AS id、 '。 $ f-> {left_key}。 ' AS left_key、 '。 $ f-> {right_key}。 ' AS right_key、 '。 $ f-> {レベル}。 ' ASレベル、 '。 $ f-> {parent_id}。 ' AS parent_id '。 「FROM」$ Table_name。 「どこ」。 ($ table-> {multi}?$ f-> {tree}。 '='。$ old-> {$ f-> {tree}}。 'AND': '')。 '('。$ f-> {left_key}。 '='。$ new-> {$ f-> {left_key}}。 'OR'。 $ f-> {right_key}。 ' = '。$ new-> {$ f-> {left_key}}。')LIMIT 1 '; #読み取り可能なリクエスト: #選択 #id AS id、 #left_key AS left_key、 #right_key AS right_key、 #レベルASレベル、 #parent_id AS parent_id #FROM $ table_name #どこ #[tree = $ tree AND] #(left_key = $ left_keyまたはright_key = $ left_key) #LIMIT 1; 私の$ sth = $ dbh-> prepare($ sql); $ sth->実行|| return {success => 0、error => $ dbh-> errstr}; 私の$ row = $ sth-> fetchrow_hashref(); $ sth-> finish; #左キーでノードが見つかったため、見つかった新しいノード if($ row && $ row-> {left_key} == $ new-> {$ f-> {left_key}}){ $ new-> {$ f-> {parent_id}} = $ row-> {parent_id}; $ new-> {$ f-> {level}} = $ row-> {level}; #ノードは正しいキーで検出されたため、新しいノードは検出されたノードの下にあります } elsif($行){ $ new-> {$ f-> {parent_id}} = $ row-> {id}; $ new-> {$ f-> {level}} = $ row-> {level} + 1; } else { #繰り返しますが、そのようながらくたは、完全に残ったデータを示しています。 ノードを最初に置くオプションがありますが、 #次に、これは間違いではありません。 しかし、他の場合には、移動を無視してください $ new-> {$ f-> {left_key}} = $ new-> {$ f-> {left_key}} && $ new-> {$ f-> {left_key}} == 1? 1:$ old-> {$ f-> {left_key}}; } } #これで、左のキーが何であるかがわかったので、内側に送信しているかどうかを確認できます if($ new-> {$ f-> {left_key}}> $ old-> {$ f-> {left_key}} && $ new-> {$ f-> {left_key}} <$ old-> {$ f-> {right_key}}){ return {success => 0、error => 'ユニットを内部に移動できません'}; } #座標を計算しましたが、唯一のものは、見て、ツリーに変更があったかどうかです if($ new-> {$ f-> {left_key}} && $ new-> {$ f-> {left_key}}!= $ old-> {$ f-> {left_key}}){ #レベルとツリーのオフセットを定義する 私の$ skew_level = $ new-> {$ f-> {level}}-$ old-> {$ f-> {level}}; 私の$ skew_tree = $ old-> {$ f-> {right_key}}-$ old-> {$ f-> {left_key}} + 1; #ツリーを下に移動する if($ new-> {$ f-> {left_key}}> $ old-> {$ f-> {left_key}}){ 私の$ skew_edit = $ new-> {$ f-> {left_key}}-$ old-> {$ f-> {left_key}}-$ skew_tree; my $ query = 'UPDATE'。$ table_name。 'SET'。$ F-> {left_key}。 ' = '。$ F-> {right_key}の場合。 <= '。$ old-> {$ f-> {right_key}}。' それから '。$ F-> {left_key}'。 + '。$ skew_edit。' 「。$ F-> {left_key}」の場合のその他の場合。 > '。$ old-> {$ f-> {right_key}}。' それから '。$ F-> {left_key}'。 -'。$ skew_tree。' ELSE '。$ F-> {left_key}'。 終了 END、 '。$ f-> {レベル}。' = '。$ F-> {right_key}の場合。 <= '。$ old-> {$ f-> {right_key}}。' THEN '。$ F-> {レベル}。 + '。$ skew_level。' ELSE '。$ F-> {レベル}'。 END、 '。$ f-> {right_key}'。 = '。$ F-> {right_key}の場合。 <= '。$ old-> {$ f-> {right_key}}。' THEN '。$ F-> {right_key}'。 + '。$ skew_edit。' 「。$ F-> {right_key}」の場合のその他の場合。 <'。$ new-> {$ f-> {left_key}}'。 THEN '。$ F-> {right_key}'。 -'。$ skew_tree。' ELSE '。$ F-> {right_key}。 終了 終了 どこ '。($ table-> {multi}?$ f-> {tree}。' = '。$ old-> {$ f-> {tree}}。' AND ':' ')。 $ f-> {right_key}。 ' > '。$ old-> {$ f-> {left_key}}。' AND '。 $ f-> {left_key}。 ' <'。$ new-> {$ f-> {left_key}}。'; '; $ dbh-> do($ query)|| return {success => 0、error => $ dbh-> errstr}; $ new-> {$ f-> {left_key}} = $ new-> {$ f-> {left_key}}-$ skew_tree; } else { #ツリーを上に移動する 私の$ skew_edit = $ new-> {$ f-> {left_key}}-$ old-> {$ f-> {left_key}}; my $ query = 'UPDATE'。$ table_name。 ' セット '。$ f-> {right_key}'。 =「。$ F-> {left_key}」の場合。 > = '。$ old-> {$ f-> {left_key}}'。 THEN '。$ F-> {right_key}'。 + '。$ skew_edit。' 「。$ F-> {right_key}」の場合のその他の場合。 <'。$ old-> {$ f-> {left_key}}'。 THEN '。$ F-> {right_key}'。 + '。$ skew_tree。' ELSE '。$ F-> {right_key}。 終了 END、 '。$ f-> {レベル}。' =「。$ F-> {left_key}」の場合。 > = '。$ old-> {$ f-> {left_key}}'。 THEN '。$ F-> {レベル}。 + '。$ skew_level。' ELSE '。$ F-> {レベル}'。 END、 '。$ f-> {left_key}'。 =「。$ F-> {left_key}」の場合。 > = '。$ old-> {$ f-> {left_key}}'。 それから '。$ F-> {left_key}'。 + '。$ skew_edit。' 「。$ F-> {left_key}」の場合のその他の場合。 > = '。$ new-> {$ f-> {left_key}}。 それから '。$ F-> {left_key}'。 + '。$ skew_tree。' ELSE '。$ F-> {left_key}'。 終了 終了 どこ '。($ table-> {multi}?$ f-> {tree}。' = '。$ old-> {$ f-> {tree}}。' AND ':' ')。 $ f-> {right_key}。 ' > = '。$ new-> {$ f-> {left_key}}。 AND '。 $ f-> {left_key}。 ' <'。$ old-> {$ f-> {right_key}}。'; '; $ dbh-> do($ query)|| return {success => 0、error => $ dbh-> errstr}; } } #まず最初に、実際に変更されたフィールドのみを$ newのままにします。 私の@sets =(); $キーをforeach(keys%{$ new}){ #そのようなフィールドはまったくありません 削除$ new-> {$ key}、次に存在しない限り$ old-> {$ key}; #コンテンツフィールドは変更されていません $ new-> {$ key}を削除、$ old-> {$ key} && $ new-> {$ key} && $ new-> {$ key} eq $ old-> {$ key}; #コンテンツのないフィールドは変更されていません 削除$ new-> {$ key}、next if!$ old-> {$ key} &&!$ new-> {$ key}; #IDは変更しませんが、念のため削除します 削除$ new-> {$ key}、次に$ key eq $ f-> {id}; #同じこと、値チェックなし @ sets、$キーを押します。 「=」。 (定義された$ new-> {$ key} && $ new-> {$ key} =〜/ ^ \ d + $ /?$ new-> {$ key}: '"'。$ new-> {$ key}。 '"'); } #変更されたフィールドを更新 my $ query = 'UPDATE'。$ table_name。 「SET」(「、」、@ setsに参加)。 'WHERE'。$ F-> {id}。 ' = '。$ old-> {$ f-> {id}}; $ dbh-> do($ query)|| return {success => 0、error => $ dbh-> errstr}; #繰り返しますが、UPDATE後に行をリクエストします。どのトリガーが更新されたかはわかりません $ sql = 'SELECT * FROM'。$ table_name。 ' WHERE '。$ F-> {id}。' = '。$ old-> {$ f-> {id}}' LIMIT 1 '; $ sth = $ dbh-> prepare($ sql); $ sth->実行|| return {success => 0、error => $ dbh-> errstr}; 私の$ row = $ sth-> fetchrow_hashref; $ sth-> finish; return {success => 1、row => $ row}; }
挿入時と同じ優先順位。 送信されるデータの妥当性もチェックされないという事実は、覚えておいてください。
Perlコード(6)
#------------------------------------------------- -------------------------------------------------- -------------------- #更新 #ツリーを下に移動する my $ update = MY :: NestedSets-> update($ table_name、{field1 => 'row-u-1-'。$ tree、ids => 1、lk => 10、tr => $ tree}); Dumper $の更新を警告します。 #ツリーを上に移動する $ update = MY :: NestedSets-> update($ table_name、{field1 => 'row-u-4-'。$ tree、ids => 6、lk => 1、tr => $ tree}); Dumper $の更新を警告します。 #親を変更 $ update = MY :: NestedSets-> update($ table_name、{field1 => 'row-u-8-'。$ tree、ids => 2、pi => 5、tr => $ tree}); Dumper $の更新を警告します。
ノードを削除
すぐにコーディング、内部のコメント:
Perlコード(7)
サブ削除{ #着信データを適切に場所に配布し、それに応じて十分なデータがあるかどうかをチェック シフトif $ _ [0] &&($ _ [0] eq __PACKAGE__ ||(ref $ _ [0] && ref $ _ [0] eq __PACKAGE__)); my($ table_name、$ id、$ flag)= @_; return {success => 0、error => 'Bad Income data!'} $ dbh && $ table_name && $ id; #どんな種類のテーブルを見つけて、追加の属性とフィールドシノニムを取得します 私の$ table = $ tables-> {$ table_name} || $ tables-> {default}; 私の$ f = $ table-> {fields}; #渡されるパラメーターの数と量のトリガーのように制限されていないため、 #削除の実装は二重になります:ブランチ全体を削除し、ツリーの1つのノードを削除します #デフォルトでは、ブランチ全体を削除します $ flag = {cascade => 'cascade'、one => 'one'}-> {$ flag || 'カスケード'} || 'カスケード'; #削除するノードを選択します。必要なフィールドは、tree、left_key、right_keyの3つだけです #それをパラメーターとして渡すことはできますが、何がわからないのか、その前にキーを変更することもできますが、 #これでツリーが崩れます。 私の$ sql = 'SELECT'。 ($テーブル-> {multi}?$ f-> {tree}。「ASツリー」: '')。 $ f-> {parent_id}。 ' AS parent_id、 '。 $ f-> {レベル}。 ' ASレベル、 '。 $ f-> {left_key}。 ' AS left_key、 '。 $ f-> {right_key}。 ' AS right_key '。 「FROM」$ Table_name。 'WHERE'。$ F-> {id}。 ' = '。$ id; 私の$ sth = $ dbh-> prepare($ sql); $ sth->実行|| return {success => 0、error => $ dbh-> errstr}; 私の古い$ $ sth-> fetchrow_hashref(); $ sth-> finish; return {success => 0、error => 'No old unit!'}} $ oldでない限り; if($ flag eq 'cascade'){ #ブランチを削除 my $ query = 'DELETE FROM'。$ table_name。 「どこ」。 ($ table-> {multi}?$ f-> {tree}。 '='。$ old-> {tree}。 'AND': '')。 $ f-> {left_key}。 ' > = '。$ old-> {left_key}。' AND '。 $ f-> {right_key}。 ' <= '。$ old-> {right_key}; $ dbh-> do($ query)|| return {success => 0、error => $ dbh-> errstr}; #キーギャップを削除します。 私の$ skew_tree = $ old-> {right_key}-$ old-> {left_key} + 1; $ query = 'UPDATE' $ table_name。 'SET'。$ F-> {left_key}。 ' =「。$ F-> {left_key}」の場合。 > '。$ old-> {left_key}。' それから '。$ F-> {left_key}'。 -'。$ skew_tree。' ELSE '。$ F-> {left_key}'。 END、 '。 $ f-> {right_key}。 ' = '。$ f-> {right_key}。' -'。$ skew_tree。 「どこ」。 ($ table-> {multi}?$ f-> {tree}。 '='。$ old-> {tree}。 'AND': '')。 $ f-> {right_key}。 ' > '。$ old-> {right_key}。'; '; #読み取り可能な形式のリクエスト: #UPDATE $ table_name #SET left_key = left_key> OLD.left_keyの場合 #THEN left_key-$ skew_tree #ELSE left_key #END、 #right_key = right_key-$ skew_tree #どこ #[tree = OLD.tree AND] #right_key> OLD.right_key; $ dbh-> do($ query)|| return {success => 0、error => $ dbh-> errstr}; } else { #ノードを削除 my $ query = 'DELETE FROM'。$ table_name。 ' WHERE '。$ F-> {id}。' = '。$ id。' LIMIT 1 '; #知らない $ dbh-> do($ query)|| return {success => 0、error => $ dbh-> errstr}; #ギャップを削除し、下位ブランチを再構築します $ query = 'UPDATE' $ table_name。 'SET'。$ F-> {left_key}。 ' =「。$ F-> {left_key}」の場合。 <'。$ old-> {left_key}。' それから '。$ F-> {left_key}'。 「。$ F-> {right_key}」の場合のその他の場合。 <'。$ old-> {right_key}。' それから '。$ F-> {left_key}'。 -1 ELSE '。$ F-> {left_key}'。 -2 終了 END、 '。 $ f-> {parent_id}。 ' = '。$ F-> {right_key}の場合。 <'。$ old-> {right_key}。 「AND」。$ F-> {レベル}。 = '。$ old-> {level}。' + 1 THEN '。$ Old-> {parent_id}' ELSE '。$ F-> {parent_id}'。 END、 '。 $ f-> {レベル}。 ' = '。$ F-> {right_key}の場合。 <'。$ old-> {right_key}。' THEN '。$ F-> {レベル}。 -1 ELSE '。$ F-> {レベル}'。 END、 '。 $ f-> {right_key}。 ' = '。$ F-> {right_key}の場合。 <'。$ old-> {right_key}。' THEN '。$ F-> {right_key}'。 -1 ELSE '。$ F-> {right_key}。 -2 終了 WHERE '。 ($ table-> {multi}?$ f-> {tree}。 '='。$ old-> {tree}。 'AND': '')。 '('。$ f-> {right_key}。 '>'。$ old-> {right_key}。 'OR ( '。$ f-> {left_key}。'> '。$ old-> {left_key}。' AND '。$ f-> {right_key}。' <'。$ old-> {right_key}。')) ; '; #読み取り可能な形式のリクエスト: #UPDATE $ table_name #SET left_key = left_key <OLD.left_keyの場合 #THEN left_key #その他の場合right_key <OLD.right_key #THEN left_key-1 #ELSE left_key-2 #END #END、 #parent_id = right_key <OLD.right_key AND `level` = OLD.level + 1の場合 #THEN OLD.parent_id #ELSE parent_id #END、 # `level` = right_key <OLD.right_keyの場合 #THEN `レベル`-1 #ELSE `レベル` #END、 #right_key = right_key <OLD.right_keyの場合 #THEN right_key-1 #ELSE right_key-2 #END #どこ #[tree = OLD.tree AND] #(right_key> OLD.right_key OR #(left_key> OLD.left_key AND right_key <OLD.right_key)); $ dbh-> do($ query)|| return {success => 0、error => $ dbh-> errstr}; } return {成功=> 1}; }
正直に言うと、結果として返すのに何が正しいかはまだわかりませんが、成功したというフラグだけで十分なようです。
Perlコード(8)
my $ delete = MY :: NestedSets-> delete($ table_name、2); $ delete = MY :: NestedSets-> delete($ table_name、3、 'one'); $ delete = MY :: NestedSets-> delete($ table_name、4);
実際にはそれだけです。 輝くフランネルの布で拭いて、行ってください。