挑戦する
ええ、あなたはボートに乗って水に乗って人生を楽しみます。 私は休息するために次の湖に行きました、そして彼らは犬やボートは許可されていないと言っているとあなたに話します、そして一般的に私たちの湖はいつも凍っています、ここであなたはスケートを持っています-お楽しみください。
「仮想ホスティング湖へようこそ。」 どういうわけか、
スーパーユーザーのみが
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);
実際にはそれだけです。 輝くフランネルの布で拭いて、行ってください。