2012-09-17 10 views
12

1対多リレーションを持つPostgreSQLには2つのテーブルがあります。私はそれらに参加する必要がありますので、それぞれの "1つ"のために、私は "多くの"テーブルから単一の結果を得るだけです。それだけでなく、 "多くの"テーブルから特定の結果を取り出す必要があります。1対多に参加して1つの結果を取得する

 
TABLE_A 
ID | NAME  | DATE   | MORE COLS.... 
1 | JOHN  | 2012-01-10 | .... 
2 | LIZA  | 2012-01-10 | .... 
3 | ANNY  | 2012-01-10 | .... 
4 | JAMES  | 2012-01-10 | .... 
... 

TABLE_B 
ID | CODE1  | CODE2  | SORT 
1 | 04020  | 85003  | 1 
1 | 04030  | 85002  | 4 
2 | 81000  | 80703  | 1 
3 | 87010  | 80102  | 4 
3 | 87010  | 84701  | 5 
4 | 04810  | 85003  | 1 
4 | 04030  | 85002  | 4 
4 | 04020  | 85003  | 1 
... 

QUERY RESULT 
ID | NAME  | DATE   | CODE1  | CODE2 
1 | JOHN  | 2012-01-10 | 04020  | 85003 
2 | LIZA  | 2012-01-10 | 81000  | 80703 
3 | ANNY  | 2012-01-10 | 87010  | 80102 
4 | JAMES  | 2012-01-10 | 04810  | 85003 
... 

TABLE_BのSORT列は、実際には並べ替えられたCODE2の最後の文字です。 CODE2は1-9で終了することができますが、3が最も重要なのは5,7,4,2,1,0,6,8,9したがって3 - > 1,5 - > 2,7 - > 3です。

私が直面している問題は、sortが最も小さい数値であるTABLE_Bから行が必要なことです。いくつかのケースでは、複数の最下位ケースがあります(TABLE_BのID = 4を参照)。最も低いIDを持つ行が選択されているかどうかは関係ありません。

+1

ようこそStackOverflow!データの表示と明確な質問をお寄せいただきありがとうございます。しかし、データをロードするための 'CREATE TABLE'ステートメントと' INSERT'ステートメントや 'COPY'ステートメントに関してデータを表示すると、あなたを助けたい人には、次回はより簡単になります。こうすることで、候補者は投稿前に簡単に候補者の回答をテストして、構文エラーがなく、必要な結果を得ていることを確認することができます。 – kgrittn

+0

ご意見ありがとうございます。私は今からそれをやるつもりです。 – thorgilsv

答えて

8

、より簡単な短い:

SELECT DISTINCT ON (a.id) 
     a.id, a.name, a.date, b.code1, b.code2 
FROM table_a a 
LEFT JOIN table_b b USING (id) 
ORDER BY a.id, b.sort 

詳細、説明、ベンチマークとthis closely related answerのリンク。
table_bに一致する行がないtable_aの行が削除されないように、LEFT JOINを使用します。

サイドノート:

のPostgreSQLで許可されているが、それは列名としてdate使用することが賢明です。すべてのSQL標準ではreserved word、PsotgreSQLではタイプ名です。

ID列の名前はidです。説明的ではなく、役に立たない。可能な命名規則の1つは、主キーのテーブルの後に名前を付けることです(table_a_id)。それを参照する外部キーの同じ名前です(他の自然名が優先されない場合)。

+0

ありがとう、この解決策もあります。列の命名は、この例で明示的な理由によるものです。 – thorgilsv

+1

@thorgilsv:わかっています。このバージョンはかなり速くなければなりません。 ['EXPLAIN ANALYZE'](http://www.postgresql.org/docs/current/interactive/sql-explain.html)でテストできます。 –

5

PostgreSQLサポートwindow functionここで私はSQL Server上でやるだろ何

SELECT d.ID, d.NAME, d.DATE, d.CODE1, d.CODE2 
FROM 
(
    SELECT a.ID, a.NAME, a.DATE, 
      b.CODE1, b.CODE2, 
      ROW_NUMBER() OVER(PARTITION BY a.ID ORDER BY b.SORT ASC, b.CODE2 DESC) AS ROWNUM 
    FROM TableA a 
      INNER JOIN TableB b 
      ON a.ID = b.ID 
) d 
WHERE d.RowNum = 1 

SQLFiddle Demo

+0

ありがとうございますが、これは私がTABLE_BからTABLE_Aに多対1で参加した場合と同じ結果をもたらします。 – thorgilsv

+0

@ user1678791 'postgresql'タグを追加して以来、' window function'を使って答えを更新しました –

+0

ユーレカ!ありがとう、これは私の質問の解決策です。 +1はSQLFiddleデモのために、ちょうど素晴らしい。 – thorgilsv

1

、これを試してみてください。速くPostgreSQLのDISTINCT ONと、

SELECT a.ID, 
    a.NAME, 
    a.DATE, 
    b.CODE1, 
    b.CODE2 
FROM TABLE_A a 
JOIN TABLE_B b 
    on a.ID = b.ID 
WHERE b.SORT = (SELECT MIN(SORT) 
    FROM TABLE_B 
    WHERE ID = b.ID) 
関連する問題