2016-08-12 21 views
0

メインテーブルがあり、他の2つのテーブルへの参照があります。これらの2つのテーブルは、参照ごとに複数のエントリを持つことがあります。完全結合で結合された左結合

メイン:

| id | mname | sid | lid | 
|----|-------|-----|-----| 
| 1 | a1 | 1 | 2 | 
| 2 | a2 | 2 | 3 | 
| 3 | a3 | 1 | 1 | 

ショート:

| id | lang | sdesc | 
|----|------|-------| 
| 1 | de | S1 | 
| 1 | en | S2 | 
| 2 | de | S3 | 
| 3 | en | S4 | 

(id, lang)はユニークです。ロング

| id | lang | ldesc | 
|----|------|-------| 
| 1 | de | L1 | 
| 1 | en | L2 | 
| 2 | de | L3 | 
| 3 | en | L4 | 

(id, lang)はユニークです。

は、私は次のような結果を持っているこれらの3つのテーブルに参加したい:

| mname | lang | sdesc | ldesc | 
|-------|------|--------|--------| 
| a1 | de | S1  | L3  | 
| a1 | en | S2  | (null) | 
| a2 | de | S3  | (null) | 
| a2 | en | (null) | L4  | 
| a3 | de | S1  | L1  | 
| a3 | en | S2  | L2  | 

私の最初の試みは、あまりにも多くのエントリを提供します(sqlfiddle

select m.mname, s.lang, s.sdesc, l.lang, l.ldesc 
from main m 
left join short_desc s on s.id = m.sid 
left join long_desc l on l.id = m.lid 

ました。

次の1は(sqlfiddle

有効なエントリを抜けて
select m.mname, s.lang, s.sdesc, l.lang, l.ldesc 
from main m 
left join short_desc s on s.id = m.sid 
left join long_desc l on l.id = m.lid 
where s.lang = l.lang 

ました。

は上記と遊んでたくさんの多くのバリエーションの後、私は望ましい結果を与える(sqlfiddle

with x1 as (select m.id, m.mname, s.lang, s.sdesc 
      from main m 
      join short_desc s on s.id = m.sid), 
    x2 as (select m.id, m.mname, l.lang, l.ldesc 
      from main m 
      join long_desc l on l.id = m.lid) 
select coalesce(x1.mname, x2.mname) mname, 
     coalesce(x1.lang, x2.lang) lang, 
     x1.sdesc, 
     x2.ldesc 
from x1 
full outer join x2 on x2.id = x1.id and x2.lang = x1.lang 

を思い付いたが、私には、このような簡単なため、過剰なようです(?)要件。

ここで私の質問ですが、簡単なアプローチがありますか?

+1

を...メインMクロスから参加(UNNEST SELECT * FROM(配列[ 'ド'、 'EN']))ラング(コード)SHORT_DESC Sに参加左s.id = m.sidとlang.code = s.lang ... ' – Abelisto

+0

あなたのデータとdesir編集結果が一致しません。あなたの結果は行a2、en、null、L4を求めますが、あなたのデータはID3に対してL4です。 – RelativePHPNewbie

+0

@RelativePHPNewbieはい、 'm.lid = l.id'、つまり' m =(2、a2,2、*、 3 *) 'と' l =(* 3 *、en、L4) ' –

答えて

1

IMO何があなたのデータスキーマに失われることは利用可能な言語の辞書です。それを導入すると、他のすべてがより簡単になります。

所望の辞書があることコールド:

  • 簡単array['en','de','fr']
  • 等定数真テーブル
  • short_desc等テーブルから言語コードを収集ビュー、long_descなど

それはありますどのような場合にはあなたの目的に適しています。例では

私たちは言語がCTEとして辞書考えるの下:

with lang(code) as (values('en'),('de'),('fr')) 
select m.*, lang.code 
from main m cross join lang; 

╔════╤═══════╤═════╤═════╤══════╗ 
║ id │ mname │ sid │ lid │ code ║ 
╠════╪═══════╪═════╪═════╪══════╣ 
║ 1 │ a1 │ 1 │ 2 │ en ║ 
║ 2 │ a2 │ 2 │ 3 │ en ║ 
║ 3 │ a3 │ 1 │ 1 │ en ║ 
║ 1 │ a1 │ 1 │ 2 │ de ║ 
║ 2 │ a2 │ 2 │ 3 │ de ║ 
║ 3 │ a3 │ 1 │ 1 │ de ║ 
║ 1 │ a1 │ 1 │ 2 │ fr ║ 
║ 2 │ a2 │ 2 │ 3 │ fr ║ 
║ 3 │ a3 │ 1 │ 1 │ fr ║ 
╚════╧═══════╧═════╧═════╧══════╝ 
(9 rows) 

あなたが見ることができるように、今、私たちは、言語ごとに個別の行と次のを持っているし、最後のステップはに、他の2つのテーブルを結合ですidlangフィールド用いて上記のクエリ: `

with lang(code) as (values('en'),('de'),('fr')) 
select m.*, lang.code, s.sdesc, l.ldesc 
from main m cross join lang 
    left join short_desc s on s.id = m.sid and s.lang = lang.code 
    left join long_desc l on l.id = m.lid and l.lang = lang.code; 

╔════╤═══════╤═════╤═════╤══════╤═══════╤═══════╗ 
║ id │ mname │ sid │ lid │ code │ sdesc │ ldesc ║ 
╠════╪═══════╪═════╪═════╪══════╪═══════╪═══════╣ 
║ 3 │ a3 │ 1 │ 1 │ de │ S1 │ L1 ║ 
║ 3 │ a3 │ 1 │ 1 │ en │ S2 │ L2 ║ 
║ 3 │ a3 │ 1 │ 1 │ fr │ ░░░░ │ ░░░░ ║ 
║ 1 │ a1 │ 1 │ 2 │ de │ S1 │ L3 ║ 
║ 1 │ a1 │ 1 │ 2 │ en │ S2 │ ░░░░ ║ 
║ 1 │ a1 │ 1 │ 2 │ fr │ ░░░░ │ ░░░░ ║ 
║ 2 │ a2 │ 2 │ 3 │ de │ S3 │ ░░░░ ║ 
║ 2 │ a2 │ 2 │ 3 │ en │ ░░░░ │ L4 ║ 
║ 2 │ a2 │ 2 │ 3 │ fr │ ░░░░ │ ░░░░ ║ 
╚════╧═══════╧═════╧═════╧══════╧═══════╧═══════╝ 
0

あなたはでlangon句の条件でleft joinをしたい:

select m.mname, s.lang, s.sdesc, l.lang, l.ldesc 
from main m left join 
    short_desc s 
    on s.id = m.sid left join 
    long_desc l 
    on l.id = m.lid and s.lang = l.lang; 

これは、行のちょうど右の数とGoldilockのソリューション、する必要があります。

あるいは:

select m.mname, s.lang, s.sdesc, l.lang, l.ldesc 
from main m left join 
    short_desc s 
    on s.id = m.sid left join 
    long_desc l 
    on l.id = m.lid and (s.lang = l.lang or s.lang is null); 
+0

これは、 'ldesc'がヌルであるエントリに対して機能し、 「a2(null)L4」の行([sqlfiddle](http://sqlfiddle.com/#!15/b3cf7/9/0))のように、 'sdesc'がヌルのエントリは除外されます。 –