#!/usr/bin/perl # MovableType で、同一カテゴリーにプライマリー・カテゴリーとサブ・カテゴリーで重複登録 # されている場合、サブ・カテゴリー登録を削除して整理するPerlスクリプト # # MovableTypeのデータベースがsqlite形式(utf8)で作成され、このスクリプトをDBファイルと # 同一のディレクトリに置いて実行すること # このスクリプト、スクリプトを実行する環境、アクセスするファイルの全てがutf8を仮定している # ため、あえて「use utf8」など行わず、文字コード変換は省いてコードをすっきりさせている。 # # ver 1.0 (C) r271-635 2017/05/05 # use strict; # 変数の宣言を強制する use warnings; use FindBin; use DBI; # DBI モジュールを利用する # このスクリプトファイルが置かれているディレクトリ名を得る my $scriptDir = $FindBin::Bin; # sqlite DBファイルのDSN(フルパス名) my $strDsn = "DBI:SQLite:dbname=" . $scriptDir . "/mtdata.db"; print "DSN =" . $strDsn . "\n"; # テーブル名 my $strTablePlacement = "mt_placement"; my $strTableCategory = "mt_category"; my $strTableEntry = "mt_entry"; main(); exit; # メイン サブルーチン sub main { my @arrayPlacementId; # 消去配列(placement_idを格納) find_overlap_placement_id( \@arrayPlacementId ); print "削除対象 " . ( $#arrayPlacementId + 1 ) . " 件, placement_id = "; foreach my $placement_id (@arrayPlacementId) { print $placement_id . ", "; } print "\n重複したこれらのカテゴリー指定を削除しますか (y) :"; $_ = ; chomp; if ( uc($_) ne 'Y' ) { die("\nユーザによりキャンセルされました。\n"); } delete_placement_record( \@arrayPlacementId ); print "\n削除完了\n"; return; } # プライマリー・カテゴリーと、サブ・カテゴリーで、同一のカテゴリー番号が指定されているIDを取得 sub find_overlap_placement_id { my ($refarrayPlacementId) = @_; my $dbh = undef; my $sth = undef; my $strQuery = ""; my @row = (); # クエリ結果を受ける配列 my $foundPlacementId = 0; # 発見されたmt_placementのID番号 eval { # DBに接続 $dbh = DBI->connect( $strDsn, "", "", { PrintError => 1, AutoCommit => 1 } ); if ( !$dbh ) { die("DBI : error open $strDsn\n"); } # 「サブ・カテゴリー」エントリーを抽出する $strQuery = "SELECT placement_id, placement_entry_id, placement_category_id " . " FROM " . $strTablePlacement . " WHERE placement_is_primary = 0"; $sth = $dbh->prepare($strQuery); $sth->execute() or die("DBI : execute error\n"); while ( my $hashref = $sth->fetchrow_hashref() ) { $foundPlacementId = get_primary_placement_id( $hashref->{'placement_entry_id'}, $hashref->{'placement_category_id'} ); if ( $foundPlacementId != 0 ) { # 消去対象のplacement_idを消去配列に格納 push( @$refarrayPlacementId, $hashref->{'placement_id'} ); # 消去対象のmt_placementデータ行を画面表示 print " ** delete ** id=" . $hashref->{'placement_id'} . ", "; print "entry_id=" . $hashref->{'placement_entry_id'} . ", "; print "category=" . $hashref->{'placement_category_id'} . ", primary=0\n"; } } $sth->finish() or die(DBI::errstr); $dbh->disconnect(); }; if ($@) { if ($dbh) { $dbh->disconnect(); } print( "DBI error : " . $@ . "\n" ); } return; } # 指定されたエントリーIDとカテゴリーIDで、プライマリー・カテゴリーに入っている場合は、そのplacement_id番号を返す sub get_primary_placement_id { my ( $entry_id, $category_id ) = @_; my $dbh = undef; my $sth = undef; my $strQuery = ""; my @row = (); # クエリ結果を受ける配列 my $foundPlacementId = 0; # 発見されたmt_placementのID番号 eval { # DBに接続 $dbh = DBI->connect( $strDsn, "", "", { PrintError => 1, AutoCommit => 1 } ); if ( !$dbh ) { die("DBI : error open $strDsn\n"); } $strQuery = "SELECT mt_placement.placement_id, mt_placement.placement_entry_id," . " mt_placement.placement_category_id, mt_placement.placement_is_primary," . " mt_entry.entry_title, mt_category.category_label " . " FROM " . $strTablePlacement . " INNER JOIN " . $strTableCategory . ", " . $strTableEntry . " ON mt_placement.placement_entry_id = mt_entry.entry_id AND " . " mt_placement.placement_category_id = mt_category.category_id " . " WHERE mt_placement.placement_entry_id = ? AND mt_placement.placement_category_id = ? AND" . " mt_placement.placement_is_primary = 1"; $sth = $dbh->prepare($strQuery); $sth->execute( $entry_id, $category_id ) or die("DBI : execute error\n"); while ( my $hashref = $sth->fetchrow_hashref() ) { $foundPlacementId = $hashref->{'placement_id'}; print "id=" . $hashref->{'placement_id'} . ", "; print "entry_id=" . $hashref->{'placement_entry_id'} . ", "; print "category=(" . $hashref->{'placement_category_id'} . ") " . $hashref->{'category_label'} . ", "; print "primary=" . $hashref->{'placement_is_primary'} . ","; print "title=" . $hashref->{'entry_title'} . "\n"; } $sth->finish() or die(DBI::errstr); $dbh->disconnect(); }; if ($@) { if ($dbh) { $dbh->disconnect(); } print( "DBI error : " . $@ . "\n" ); } return ($foundPlacementId); } # mt_placementテーブルより、引数で指定された配列の各要素で示されるplacement_id行を全て削除する sub delete_placement_record { my ($refarrayPlacementId) = @_; print "削除要素数 : " . @$refarrayPlacementId . "個 削除中 ...\n"; my $dbh = undef; my $sth = undef; my $strQuery = ""; eval { # DBに接続 $dbh = DBI->connect( $strDsn, "", "", { PrintError => 1, AutoCommit => 0 } ); if ( !$dbh ) { die("DBI : error open $strDsn\n"); } $strQuery = "DELETE FROM " . $strTablePlacement . " WHERE placement_id = ?"; $sth = $dbh->prepare($strQuery); foreach my $placement_id (@$refarrayPlacementId) { my $result = $sth->execute($placement_id) or die("DBI : execute error\n"); if ( $result == 1 ) { print ", " . $placement_id; } else { print ", ERROR[" . $placement_id . "]"; } } $sth->finish() or die(DBI::errstr); $dbh->commit(); $dbh->disconnect(); }; if ($@) { if ($dbh) { $dbh->disconnect(); } print( "\nDBI error : " . $@ . "\n" ); } return; }