2012-12-19 10 views
8

以下の私の例では、2つのLEFT JOINを使って "event_name"にアクセスすると重複しています。私はこのように設定して112ケースを取得します。しかし、2 LEFT JOIN行を取り除いてクエリを実行すると、重複しない適切な100レコードが得られます。私は以下のコードでDISTINCTを試みましたが、私はまだ重複して112を取得します。3つの結合テーブル全体でSQLクエリで重複を避ける方法

SELECT "cases"."id", "cases"."date", "cases"."name", "event"."event_name" 
FROM "cases" 
LEFT JOIN "middle_table" ON "cases"."serial" = "middle_table"."m_serial" 
LEFT JOIN "event" ON "middle_table"."e_serial" = "event"."ev_serial" 
WHERE "cases"."date" BETWEEN '2012-12-11' AND '2012-12-13' 

どのように私は私が唯一の「例」から正確な100例を望んでいることを指定し、私はより多くの行を生成するために参加するには、テーブルから何もしたくないことができますか?

ありがとうございます!

+1

どのように関連して次のようにあなたは、(通常、COUNTやSUMなどの機能を、照合のために使用されている)「GROUP BY」キーワードを使用して、ユニークな値の選択を制限することができますか? 1: 'cases'から' middle_table'までのN?あなたはそれについて少し教えていただけますか? –

+0

いくつかのテストデータを提供できますか? [sql-fiddle](http://www.sqlfiddle.com)はこれに最適です。 – Nico

+1

私の場合は、1対多の結合で結合するために重複していました。私が見つけることができる唯一の解決策は、サブクエリを使用することでした。 Aには多くのBsがあります。 Bには多くのCと多くのDがあります。 Dには多くのEsと多くのFがあります。私はすべてのBs(検索文字列にマッチする)を取得する必要がありました。また、各マッチのすべての関連するCs、Es、Fsを集計しました。私は外部結合を使用してABCを取得し、次に2つのサブクエリを使用してDEとDFを集計しました。 – bambams

答えて

7
あなたが条件に一致する middle_tableで唯一のエントリーがあり、それは middle_tableの各エントリのために eventで唯一のエントリがある casesの各エントリのように条件を含めるようにON句を拡張する必要があり

LEFT JOIN middle_table ON cases.serial = middle_table.m_serial AND some_condition 

もちろん、DISTINCTを使用できます。それがうまくいかない場合は、フィールドcases.idcases.datecases.nameおよびevent.event_nameのすべての結果が異なることを意味します。結果を調べ、捨てたい項目を決定し、ON句にその条件を含める。

+0

こんにちはAndreKR、私はJohnLBevanの投稿に次のように言いました。 あなたは理論的条件を与えることができますか? Max関数が「選択した列の最大値を返す」ということを理解しました。 ジョイントテーブルの一方または両方のidフィールドでこれを使用する簡単な方法はありますか? – Chain

+0

これらの3つの手法のうちの1つを使用する必要があります:http://dev.mysql.com/doc/refman/5.5/en/example-maximum-column-group-row.htmlしかし、それらが本当に同一であった場合、 DISTINCTはそれらをフィルタリングしてしまいました。 – AndreKR

+0

上記のリンクはMySQLに固有のものですが、おそらく他のシステムでも動作することに注意してください。とにかくあなたの質問に使用しているDBMSを常に述べるべきです。 – AndreKR

5

あなたが参加しているテーブルに複数の一致があります。効果的にコードには次のように書かれています:

select * 
from parent 
left outer join child on parent.id = child.parentId 

親に2人の子供がいる場合は、その両方を取得します。親は2回現れます。

妥協する必要がある場合にのみ親を取得したい場合は、両方の子供を持つことはできません。

select p.id, p.name, max(c.id), max(c.name) --nb: child id and name may come from different records 
from parent p 
left outer join child c on parent.id = child.parentId 
group by p.id, p.name 

または

:例えば、以下のように、外側の文の中で、子テーブルから列に集約関数を実行し、親テーブルから列にしてグループを行う、または内部の文と where r=1rownumber() over partition by (list,of,parent,columns order by list,of,child,columns) rを使用しますか
select * 
from 
(
    select p.id, p.name, c.id, c.name 
    , rownumber() over (partition by p.id order by c.id desc) r 
    from parent p 
    left outer join child c on parent.id = child.parentId 
) x 
where x.r = 1 

UPDATE子データが正確にあなたがこれを行うことができます同じであれば、コメントで述べたように

select p.id, p.name, c.name 
from parent p 
left outer join 
(
    select distinct c.parentId, c.name 
    from child 
) c on parent.id = child.parentId 

か(いくつかのフィールドは異なりますが、あなたはあなたが得るどの気にしない場合)

select p.id, p.name, c.id, c.name 
from parent p 
left outer join 
(
    select max(c.id) id, c.parentId, c.name 
    from child 
    group by c.parentId, c.name 
) c on parent.id = child.parentId 
+0

ps。 @AndreKRも良い提案です。条件付き論理を結合に追加して、結果を親当たり1つの子の最大値に制限する。 – JohnLBevan

+0

こんにちは、私はそのほとんどを理解していると思います。はい:私の場合、両親の中には複数の子供がいますが、病院の中間テーブルやイベントテーブルには何らかの冗長性があります。基本的に、特定の両親の両方の子供は正確な重複しているので、私はどちらの子も同じであるので、私が選んだ子供は気にしません。 – Chain

+0

その場合は上記のいずれかが良いです(2番目の方法がおそらく効率的です)。代わりに、重複した子を早期にフィルターに掛けることもできます(別のステートメントが機能していないと思われますが、子レベルで返されるものにはいくつかの違いがあります。 – JohnLBevan

1

重複が「用「middle_table」と「イベント」のために複数のフィールドを持っていることの結果でありますケース "。テーブルは

SELECT "cases"."id", "cases"."date", "cases"."name", "event"."event_name" 
FROM "cases" 
LEFT JOIN "middle_table" ON "cases"."serial" = "middle_table"."m_serial" 
LEFT JOIN "event" ON "middle_table"."e_serial" = "event"."ev_serial" 
GROUP BY "cases"."id", "cases"."date", "cases"."name", "event"."event_name" 
WHERE "cases"."date" BETWEEN '2012-12-11' AND '2012-12-13' 
関連する問題