16

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

表_A
身份证 | 姓名 | 日期 | 更多科尔斯....
1 | 约翰 | 2012-01-10 | ……
2 | 丽莎 | 2012-01-10 | ……
3 | 安妮 | 2012-01-10 | ……
4 | 詹姆斯 | 2012-01-10 | ……
...

表_B
身份证 | 代码1 | 代码2 | 种类
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
...

查询结果
身份证 | 姓名 | 日期 | 代码1 | 代码2
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 等等向前。

我面临的问题是我需要 TABLE_B 中排序是最低数字的行。在某些情况下,有多个最小情况(请参阅 TABLE_B 中的 ID=4),那么选择具有最低 ID 的哪一行并不重要,只要该 ID 有一个结果即可。

4

3 回答 3

16

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

这个密切相关的答案中的详细信息、解释、基准和链接。
我使用 a LEFT JOIN,因此不会删除table_a没有任何匹配行的行。table_b

旁注:

date虽然在 PostgreSQL 中被允许,但将其用作列名是不明智的。它是每个 SQL 标准中的保留字,也是 PsotgreSQL 中的类型名称。

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

于 2012-09-18T01:43:28.180 回答
7

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 演示

于 2012-09-17T23:55:27.770 回答
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)
于 2012-09-18T00:10:42.090 回答