web-dev-qa-db-ja.com

1対多で結合し、単一の結果を取得します

PostgreSQLには、1対多の関係を持つ2つのテーブルがあります。 「1つ」ごとに「多く」のテーブルから1つの結果しか得られないように、それらを結合する必要があります。それだけでなく、「多くの」テーブルから特定の結果を特定する必要があります。

 TABLE_A 
 ID |名前|日付|その他のCOLS .... 
 1 |ジョン| 2012-01-10 | .... 
 2 |リザ| 2012-01-10 | .... 
 3 |アニー| 2012-01-10 | .... 
 4 |ジェームス| 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 |名前|日付| CODE1 | CODE2 
 1 |ジョン| 2012-01-10 | 04020 | 85003 
 2 |リザ| 2012-01-10 | 81000 | 80703 
 3 |アニー| 2012-01-10 | 87010 | 80102 
 4 |ジェームス| 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の行のどれを選択してもかまいませんが、そのIDの結果は1つだけです。

14
thorgilsv

PostgreSQLのDISTINCT ONを使用すると、よりシンプルに、より短く、より速くなります。

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

詳細、説明、ベンチマーク、および この密接に関連する回答 のリンク。
私はLEFT JOINを使用しているので、table_aに一致する行がないtable_bの行は削除されません。

サイドノート:

PostgreSQLでは許可されていますが、列名としてdateを使用することは賢明ではありません。これは、すべてのSQL標準では 予約語 であり、PsotgreSQLでは型名です。

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

10

PostgreSQLはウィンドウ関数をサポートします。これを試して、

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デモ

6
John Woo

これが私がSQLServerで行うことです。

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)
2
Bacon Bits