我有两个表,如果重要的话,在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有单个结果。
答案 0 :(得分:10)
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
答案 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)