Scuttle を設置していたら、スパム投稿がやたら多くなってきた。スパムを投稿するために登録された「迷惑なユーザ」を削除し、そのユーザが投稿したブックマーク、タグを削除したい。
対象
Scuttle 0.7.1
MySQL 4.0
PHP 4
方法
まず、phpMyAdmin で、sc_users テーブル における「迷惑なユーザ」を削除した。
Scuttle のデータベースを見たら、以下のような構造になっていた。(接頭辞 sc_ は省略してある。)
迷惑なユーザを消したので、次に、bookmarks テーブル の要素において、users テーブルの要素に対する参照を持たないレコードを削除しようとした。
DELETE FROM sc_bookmarks WHERE NOT EXISTS (SELECT * FROM sc_users WHERE bookmarks.uId = users.uId)
しかし、この DELETE 文は、実行できなかった。
MySQL AB :: MySQL 4.1 リファレンスマニュアル :: 6.4.2.11 初期の MySQL バージョンに合わせたサブクエリの書き換え によると、
上記の文は「t1 の要素の中で、t2 と結合しない要素を取得する」を意味している。これを「table1 に table2 を外部結合したとき、table2 の中で table1 に対する参照を持たないものを取得する」に読み替えている。 これを参考にして、次のように記述を変更した。バージョン 4.0 までは、ネストされたクエリのサポートは、
INSERT ... SELECT ...形式とREPLACE ... SELECT ...形式だけに限定されています。...SELECT * FROM t1 WHERE id NOT IN (SELECT id FROM t2); SELECT * FROM t1 WHERE NOT EXISTS (SELECT id FROM t2 WHERE t1.id=t2.id);
次のように書き換えることができます。
SELECT table1.* FROM table1 LEFT JOIN table2 ON table1.id=table2.id WHERE table2.id IS NULL;
SELECT sc_bookmarks.bId FROM sc_bookmarks LEFT JOIN sc_users ON sc_bookmarks.uId = sc_users.uId WHERE sc_users.uId IS NULL
また、同上によると、
より複雑なサブクエリでは、多くの場合、サブクエリを保持するためのテンポラリテーブルを作成することができます。しかし、一部のケースでは、この方法は有効ではありません。このようなケースの多くは、DELETEステートメントで発生します。この場合、標準 SQL では、結合をサポートしていません(サブクエリ内を除く)。この状況には、次の 3 つの方法のいずれかで対処することができます。
- 第 1 の選択肢: MySQL バージョン 4.1 にアップグレードする。
- 第 2 の選択肢: 手続き型プログラミング言語(Perl や PHP など)を使用し、
SELECTクエリを送信して削除対象のレコードの主キーを取得し、その後、それらの値を使用してDELETEステートメント(DELETE FROM ... WHERE ... IN (key1, key2, ...))を構築する。- 第 3 の選択肢: 対話式 SQL で、MySQL の拡張
CONCAT()を使用して(標準の||演算子の代わりに)、DELETEステートメントのセットを自動で構築する。
第2の選択肢を取ることにした。
以下のコードを index.php というファイルにして保存し、サーバの適当なディレクトリに配置し、ブラウザでアクセスした。 DELETE 文は、バスンと一気に削除するので、気をつけて使用した。
<?php
$server = ""; // サーバ
$userName = ""; // ユーザ名
$passwd = ""; // パスワード
$dbName = ""; // データベース名
// データベースに接続する。
if ($db = mysql_connect($server, $userName, $passwd)){
mysql_select_db($dbName, $db);
// 迷惑なユーザを削除してあるので、sc_bookmarks に sc_users を外部結合させると、
// sc_usres の uID が NULL のブックマークが見つかる。
//
// ※ このように記述したのは、MySQL のバージョンが 4.1 よりも古いため。
// 参考: http://dev.mysql.com/doc/refman/4.1/ja/rewriting-subqueries.html
$sql_bm = "SELECT sc_bookmarks.bId FROM sc_bookmarks LEFT JOIN sc_users ON sc_bookmarks.uId = sc_users.uId WHERE sc_users.uId IS NULL";
// sc_users に存在しない uID を持つブックマークの配列を取得する。
$rows = mysql_query($sql_bm, $db);
$counter_bm = 0;
while ($row = mysql_fetch_array($rows)){
// ブックマークを削除する。
mysql_query("DELETE FROM sc_bookmarks WHERE bId = '" . $row["bId"] ."'", $db);
$counter_bm++;
}
echo "$counter_bm 件のブックマークを削除しました。";
// 迷惑なユーザのブックマークを削除してあるので、sc_tags に sc_bookmarks を外部結合させると、
// sc_bookmarks の bID が NULL のブックマークが見つかる。
$sql_tag = "SELECT sc_tags.id FROM sc_tags LEFT JOIN sc_bookmarks ON sc_tags.bid = sc_bookmarks.bId WHERE sc_bookmarks.bId IS NULL";
// sc_bookmarks に存在しない bID を持つタグの配列を取得する。
$rows = mysql_query($sql_tag, $db);
$counter_tag = 0;
while ($row = mysql_fetch_array($rows)){
$counter_tag++;
// ブックマークについているタグを削除する。
mysql_query("DELETE FROM sc_tags WHERE id='" . $row["id"] . "'", $db);
}
echo "$counter_tag 件のタグを削除しました。";
} else {
echo "データベースに接続できませんでした。";
}
?>
0コメント:
コメントを投稿