从一个表中选择具有相关表聚合的字段

时间:2016-01-25 00:30:22

标签: sql postgresql subquery inner-join aggregate

以下是2个表格的简要说明:

CREATE TABLE jobs(id PRIMARY KEY, description);
CREATE TABLE dates(id PRIMARY KEY, job REFERENCES jobs(id), date);

每份工作可能有一个或多个日期。

我想创建一个生成以下内容的查询(在pidgin中):

jobs.id, jobs.description, min(dates.date) as start, max(dates.date) as finish

我尝试过这样的事情:

SELECT id, description,
      (SELECT min(date) as start  FROM dates d WHERE d.job=j.id),
      (SELECT max(date) as finish FROM dates d WHERE d.job=j.id)
FROM jobs j;

有效,但看起来效率很低。

我尝试了INNER JOIN,但看不到如何在jobs上使用合适的汇总查询加入dates

有人能建议一种干净有效的方法吗?

2 个答案:

答案 0 :(得分:1)

检索所有行时:首先聚合,稍后加入:

SELECT id, j.description, d.start, d.finish
FROM   jobs j
LEFT   JOIN (
   SELECT job AS id, min(date) AS start, max(date) AS finish 
   FROM   dates 
   GROUP  BY job
   ) d USING (id);

相关:

关于JOIN .. USING

这不是“不同类型的加入”。 USING (col)ON a.col = b.col 标准SQL (!)语法快捷方式。更确切地说,quoting the manual:

  

USING子句是一种允许您利用的简写   连接双方使用相同名称的具体情况   对于连接列。它需要以逗号分隔的列表   共享列名并形成包含的连接条件   每个人的平等比较。例如,加入 T1 T2   USING (a, b)生成连接条件ON *T1*.a = *T2*.a AND *T1*.b = *T2*.b

     

此外,JOIN USING的输出会抑制冗余列:   没有必要打印两个匹配的列,因为它们必须   有相同的价值观。虽然JOIN ON生成了来自 T1 的所有列   通过 T2 的所有列,JOIN USING为每个列生成一个输出列   列出的列对(按列出的顺序),后跟任何   来自 T1 的剩余列,然后是来自 T2 的剩余列。

您可以编写SELECT * FROM ...并且加入列只列出一次特别方便。

答案 1 :(得分:1)

Erwin's solution外,您还可以使用window clause

SELECT j.id, j.description,
       first_value(d.date) OVER w AS start,
       last_value(d.date) OVER w AS finish
FROM jobs j
JOIN dates d ON d.job = j.id
WINDOW w AS (PARTITION BY j.id ORDER BY d.date
            ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING);

窗口函数有效地按一列或多列(PARTITION BY子句)和/或ORDER BY其他列进行分组,然后您可以对其应用一些window function,甚至是常规列聚合函数,不影响任何其他列的分组或排序(在您的情况下为description)。它需要一种不同的构造查询的方式,但是一旦你明白它就会非常出色。

在您的情况下,您需要获取分区的第一个值,这很容易,因为默认情况下它是可访问的。您还需要超越窗口框架(默认情况下以当前行结束)到分区中的最后一个值,然后您需要ROWS条款。由于使用相同的窗口定义生成两列,因此此处使用WINDOW子句;如果它适用于单个列,您可以在选择列表中编写窗口函数,然后是OVER子句和不带名称的窗口定义(WINDOW w AS (...))。