加入一对多并检索单个结果

时间:2012-09-17 23:50:00

标签: sql postgresql select join one-to-many

我有两个表,如果重要的话,在PostgreSQL中有一对多关系。我需要加入它们,以便对于每个“one”我只从“many”表中得到单个结果。不仅如此,我还需要从“许多”表中挑选出具体的结果。

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-> 1。 3等等。

我面临的问题是我需要TABLE_B中的行,其中sort是最小的数字。在某些情况下,有多个最小的情况(参见TABLE_B中的ID = 4),然后选择具有最低ID的哪个行并不重要,只有该ID有单个结果。

3 个答案:

答案 0 :(得分:10)

使用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

this closely related answer中的详细信息,说明,基准和链接 我使用了LEFT JOIN,因此table_a中没有任何匹配行的table_b行不会被删除。

附注:

虽然在PostgreSQL中被允许,但使用date作为列名是不明智的。它是每个SQL标准中的reserved word和PsotgreSQL中的类型名称。

命名ID列id也是一种反模式。不具有描述性,也没有帮助。一个(许多)可能的命​​名约定是在它是主键的表之后命名它:table_a_id。引用它的外键的名称相同(如果没有其他自然名称优先)。

答案 1 :(得分:6)

PostgreSQL支持 window function 。试试这个,

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

答案 2 :(得分:2)

这是我在SQL Server上做的事情。

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)