2009-08-17 15 views
11

返す情報を扱うサブクエリやジョイントなどで変更された結果を返すSQL文を作成するにはどうすればよいですか?例えばSQL:*異なる*行の値に基づいて行を選択するための "NOT IN"代替?

CREATE TABLE bowlers (
bowling_id int4 not null primary key auto_increment, 
name text, 
team text 
); 

誰かが間違って複数のチームであるかもしれない:

INSERT INTO `bowlers` (`name`, `team`) VALUES 
('homer', 'pin pals'), 
('moe', 'pin pals'), 
('carl', 'pin pals'), 
('lenny', 'pin pals'), 
('homer', 'The homer team'), 
('bart', 'The homer team'), 
('maggie', 'The homer team'), 
('lisa', 'The homer team'), 
('marge', 'The homer team'), 
('that weird french guy', 'The homer team'); 

のでhomerは、彼のチームを決定することはできませんので、彼は両方にあります。 Do'h!

the homer teamにいるすべての人を知りたいのですが、pin palsチームに所属していない人もいます。私ができる最善のはこれです:

SELECT a.name, a.team 
    FROM bowlers a where a.team = 'The homer team' 
    AND a.name 
    NOT IN (SELECT b.name FROM bowlers b WHERE b.team = 'pin pals'); 

がで結果の:あなたが知っている、

+-----------------------+----------------+ 
| name     | team   | 
+-----------------------+----------------+ 
| bart     | The homer team | 
| maggie    | The homer team | 
| lisa     | The homer team | 
| marge     | The homer team | 
| that weird french guy | The homer team | 
+-----------------------+----------------+ 
5 rows in set (0.00 sec) 

、華麗!

パフォーマンスが数千人の数百人のために、いくつかの行のためのD.グレートにAにBでクエリのサブクエリは、のために実行されようとしている各結果として、かなり悪い苦しむことになります行。

もっと良い方法はありますか?私は主に自己参加がトリックをすると考えていますが、私はそれをどうやって行うかについて私の頭を包み込むことはできません。

はこれを行うには、他の方法があり、また、NOT IN(SELECT ...)

を使用せずに、この種の問題のための名前は何ですか?

+1

あなた自身に戻って左外部結合があなたの望むものです。 –

答えて

15

SELECT a.name, a.team 
FROM bowlers a 
LEFT OUTER JOIN bowlers b ON a.name = b.name AND b.team = 'pin pals' 
WHERE a.team = 'The homer team' 
AND b.name IS NULL; 

ます。また、このようにそれを行うことができます:ところで

SELECT a.name, a.team 
FROM bowlers a 
WHERE a.team = 'The homer team' 
AND NOT EXISTS (SELECT * FROM bowlers b 
    WHERE b.team = 'pin pals' 
    AND a.name = b.name 
    ); 

、これは "左反半結合" と呼ばれています。

+0

Brilliant!あなたの最初の例は確かに私の問題の改善です。まだ少し遅い(MySQLバージョン5.0.37)が稼働していますが、いくつかは...少なくとも今は復帰しています! このことを説明してくれてありがとうございました(左のアンチ・セミ・ジョイン) –

2

LEFT JOINとすることができます。結合されたテーブルにはデータがありません(すべてがnullです)。このよう

SELECT a.name, a.team 
    FROM bowlers a 
    LEFT JOIN bowlers b 
     ON b.name = a.name AND b.team = 'pin pals' 
    WHERE a.team = 'The homer team' 
    AND a.name 
    -- the join has to fail for this to be null 
    AND b.bowling_id IS NULL 
+0

これは間違いなく機能しますが、サブクエリよりも効率的ですか?参加にもっとオーバーヘッドがあるようですが、わかりません。 – chrissr

+0

テーブル構造、使用可能なインデックス、テーブル内の行数など、チームAまたはチームBに含まれる人の数に大きく依存します。 –

関連する問題