以下是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
。
有人能建议一种干净有效的方法吗?
答案 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 (...)
)。