古いMySQL(4.1)と格闘したメモ

以下、大したことじゃないし、正解とも思えないので、よっぽど暇な方以外は読まないで下さい。
2つのテーブル user_listとmailboxがあって、それらのエントリーの関係をまとめた第3のテーブルcheck_listがあるとする。check_list.uid は user_list.idと対応し、check_list.mail_idは mailbox.idと対応する。こんな↓感じ。

CREATE TABLE 'user_list' (
'id'     int,
'user_name'  varchar(256),
'email' varchar(256)
);

CREATE TABLE 'mailbox' (
'id'     int,
'addr' varchar(256),
'content' varcahr(256)
);

CREATE TABLE 'check_list' (
'u_id'     int,
'mail_id'  int,
'relation' varchar(256)
);

ここで、ややこしいのは、user_listもmailboxもメールアドレスを含んでいること。

やりたかったこと

user_list.email = mailbox.addr の関係にある check_listのエントリを探し出し、そのエントリのmail_idに相当する mailboxのエントリが1個しかないケースを検索したい。

やってみたこと

こんなSQL文になった。

SELECT check_list.mail_id, COUNT(*), mailbox.addr 
FROM check_list, mailbox 
WHERE check_list.mail_id = mailbox.id 
AND check_list.mail_id IN 
 (SELECT check_list.mail_id  
  FROM user_list, mailbox, check_list  
  WHERE check_list.u_id = maia_users.id  
  AND check_list.mail_id = mailbox.id
  AND user_list.user_name = mailbox.addr  
  AND check_list.relation ='1') 
GROUP BY check_list.mail_id;

実は「1個しかないケース」というのをちゃんと書けなかったのだが、これでも、サブクエリーの結果がキャッシュされないのか、えらく遅かった。

本当はこんなふうに書きたかった

これもえらく遅くて、結局一度も完了しなかった。

SELECT check_list.mail_id, mailbox.addr
FROM check_list, mailbox 
WHERE check_list.mail_id = mailbox.id 
AND (check_list.mail_id, 1, mailbox.addr) IN 
(SELECT check_list.mail_id, COUNT(*), mailbox.addr 
  FROM check_list, mailbox 
  WHERE check_list.mail_id = mailbox.id 
  AND check_list.mail_id IN 
   (SELECT check_list.mail_id  
    FROM user_list, mailbox, check_list  
    WHERE check_list.u_id = maia_users.id  
    AND check_list.mail_id = mailbox.id
    AND user_list.user_name = mailbox.addr  
    AND check_list.relation ='1') 
  GROUP BY check_list.mail_id);

VIEWが記述できるようなデータベースを使うか、一時テーブルを使えばよかったのだろう。
つまり、最初のクエリの結果を、テーブルに格納して、それに対してシンプルなクエリを実行すればよかったのだと思う。(試してはいない)
さすがにこうすれば、temp1の内容を再計算したりはすまい。
参照:MySQL :: MySQL 4.1 リファレンスマニュアル :: 6.5.3 CREATE TABLE 構文

CREATE TEMPORALY TABLE temp1
SELECT check_list.mail_id AS t_id, COUNT(*) AS t_count, mailbox.addr AS t_addr
FROM check_list, mailbox 
WHERE check_list.mail_id = mailbox.id 
AND check_list.mail_id IN 
 (SELECT check_list.mail_id  
  FROM user_list, mailbox, check_list  
  WHERE check_list.u_id = maia_users.id  
  AND check_list.mail_id = mailbox.id
  AND user_list.user_name = mailbox.addr  
  AND check_list.relation ='1') 
GROUP BY check_list.mail_id;

SELECT t_id, t_addr
FROM temp1 
WHERE t_count = 1;