2012-03-29 8 views
4

私は書き込みしようとしているSQLクエリを持っていますが、それを動作させる方法はあまりよく分かりません。トリッキーなSQLクエリ、多分何らかの種類の結合がうまくいくでしょうか?

私は3つのテーブルがあります: "S" と "t" の間のマップである "S"、 "T"、および "ST"(

table s 
======= 
primary key sID | val 
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ 
     a    0 
     b    1 
     c    5 
     d    6 
     e    7 



table t 
======= 
primary key tID | val 
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ 
     nul    -1 
     bbb    2 
     ccc    3 
     ddd    4 



table st 
======== 
foreign key sID | foreign key tID 
(unique)   | (multiple sID to one tID, meaning tID is not unique) 
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ 
     a     ddd 
     b     ccc 
     c     nul 
     d     ccc 
     e     bbb 

だから、すべての 'S' がする必要があるが。 't'にマッピングされるが、実際の 't'にはマッピングされないものはデフォルト/ null 't'(nul)にマッピングされる。 'という意味です。つまり、テーブル' s 'が1の場合、テーブル' t 'は1を持つことはできません。


私の問題は次のようなものです: valのセット( 's'または 't'のいずれか)を指定すると、対応するIDの 'st'テーブルでsIDとtIDを取得する必要があります。問題は、 's'がセットに含まれているが、 't'がセットにない場合、(sID、tID)ではなく値(sID、 'nul')を取得する必要があるということです。

たとえば、値(3,1,6)が指定されていると、次のペアが返されます。(b、ccc); (d、ccc);値(0,4)を考える

、それが対を返すであろう:(DDD)

しかし、値(6)が与えられると、それは(D、NUL)を返す必要があるからですval 3(これはcccに対応し、dは何にマップされているか)はセットに含まれていません。私はnull 's'は必要ありません、ちょうどnull 't'です。


私は、次のステートメントを使用して考えていたが、唯一の 'の集合ではなく、「T」である場合には戻る「ID、NUL」で私を助けていません。

私に「T」とセットで「S」(実際にそれが私のセット内にある任意の「T」に関連付けられているすべての年代 "を与える)の両方を持っている何かを与え
SELECT st.sID, st.tID FROM t, st WHERE t.tID=st.tID AND (t.val=%_VAL1_% OR t.val=%_VAL_2 OR ......); 

、それ私には自分自身である 's'を与えません。

「s」にはあるが「st」にはないものは後処理することができるかもしれませんが、可能ならばそれを避けたいと思います。

誰にも提案はありますか?私はむしろ立ち往生している。

ありがとうございます!

(注:S、T、およびstは心配しないでください、私の本当のテーブル名ではありません。また、主キーの実際残念ながら、GUIDをテキストが、私は区別することを簡単にするために試される)

+0

私はあなたのモデルとデータから、それは間違って届かない場合は、私はあなたが1対多の関係をモデル化するための3つのテーブルを持って見ることができます。なぜ2つだけ使ってみませんか? 'all 's'を 't'にマッピングしなければならないと言ったのですが、なぜFKを 's'の 't'に追加しないのですか? –

+0

これは、主に、拡張性の目的と、インターフェイスをsqliteを使用する前の状態と多少似ているように維持するためのものでした。 – Jordan

+0

このデータベースモデルはかなり奇妙に見えます。その動機についてもっと分かち合うことができますか?おそらく別のモデルがあなたに役立つだろうか?また、 'st'に存在する行' {c、null} 'とそのような行がまったく存在しないことの違いは何ですか? –

答えて

3

は、あなたが望むものである:ここでは

SELECT s.sID, t.tID 
FROM st 
    LEFT JOIN s 
     ON s.sID = st.sID AND s.val IN (6) 
    LEFT JOIN t 
     ON t.tID = st.tID AND t.val IN (6) 
WHERE NOT(s.sid IS NULL AND t.tid IS NULL) 

がです。結果セットはヌルになる可能性があるため、マッピングテーブルをメインにする必要があります。

しかし、これは非常に奇妙なロジックです。通常、マッピングが多対多関係でヒットしない場合は、部分的ではなく0行を返します。

複数のマッピングミスから発生する可能性のある重複を取り消したい場合は、 1列の出力)、DISTINCTを追加します。

SELECT DISTINCT s.sID, t.tID 
FROM st 
    LEFT JOIN s 
     ON s.sID = st.sID AND s.val IN (6) 
    LEFT JOIN t 
     ON t.tID = st.tID AND t.val IN (6) 
WHERE NOT(s.sid IS NULL AND t.tid IS NULL) 

Here is the fiddle that shows the duplication

And, here is the one that fixes it

、そして最後に、最新のアップデートに基づいて:このように。 NULLの列を除外したい場合は、INNER JOINを作成して、次にNULLを取得しないのでNULLチェックを取り除くことができます。sID|NULLの結果が必要な場合は、 。

SELECT DISTINCT s.sID, t.tID 
FROM st 
    JOIN s 
     ON s.sID = st.sID AND s.val IN (6) 
    LEFT JOIN t 
     ON t.tID = st.tID AND t.val IN (6) 

Here is the SQLFiddle

+0

からstを持っていなければなりません。それはどちらかといえばうまくいくようには見えませんが、ちょうど6の場合(ヌル行を返します)しかし、私が(6,3)を使用すると、正しいvalを返してからヌル行が1つ返され、nullのsIDではなく同じtID(ccc)の行が返されるように見えます。奇妙なロジック:p – Jordan

+1

sqlfiddleがヌル結果をたくさん隠しているので、最後に 'WHERE NOT(s.sid IS NULLとt.tid IS NULL)'を追加するとよいでしょう。 –

+0

@JoachimIsakssonそうです。コードが更新され、まもなく新しいSQLフィドルリンクが追加されます –

0

あなたはLEFT JOINを探している:ここで

SELECT s.sid AS sid, t.tid AS tid 
    FROM s 
    LEFT JOIN st 
    ON s.sid = st.sid 
    LEFT JOIN t 
    ON t.tid = st.tid 
WHERE s.val IN (3, 1, 6) 
    AND t.val IN (3, 1, 6) 
+0

これはちょうど6 –

+0

Yupを使用している場合には機能しません。それは問題です。私はちょうど "6"を使用する場合、それは全体のセットを返します(d、ccc) – Jordan

+0

これは私のsqlfiddleセットアップに対して試してみてください。ここでsまたはtはnullになる可能性があるので、 –

関連する問題