如何在引用 table 的列中查询具有最大值的行?

How to query row with max value in a column in a referencing table?

有一些流行的情况,需要从 table 中 select 具有最大值(或最小值或其他聚合函数结果)的行。我的情况更复杂 - 它在图片中添加了 JOIN

这是一个例子:

CREATE TABLE spacecraft (
  id   serial PRIMARY KEY, 
  name text NOT NULL
);

CREATE TABLE launch (
  id            serial PRIMARY KEY,
  spacecraft_id int REFERENCES spacecraft(id) NOT NULL,
  started       timestamptz NOT NULL,
  success       bool NOT NULL
);

INSERT INTO spacecraft (id, name) VALUES 
    (1, 'Bebop'), 
    (2, 'Serenity'), 
    (3, 'Death Start');

INSERT INTO launch (spacecraft_id, started, success) VALUES 
    (1, 'January 8 04:05:06 2999 UTC', true), 
    (2, 'December 1 01:00:00 3432 UTC', true), 
    (3, 'February 15 00:00:00 4521 UTC', false), 
    (3, 'July 10 12:05:00 4525 UTC', true);

http://sqlfiddle.com/#!15/a1921

如何select每个航天器的最后发射结果(launch.success)?

更新 #1

这是我目前的解决方案:

SELECT DISTINCT S.*, last_launch, L2.success FROM spacecraft AS S
LEFT OUTER JOIN (SELECT *, MAX(started) OVER (PARTITION BY spacecraft_id) AS last_launch FROM launch) AS L1
ON L1.spacecraft_id=S.id
LEFT OUTER JOIN launch AS L2
ON L2.started=L1.last_launch;

http://sqlfiddle.com/#!15/45618/38

如果你只想获得最大的成功,那么你已经添加了一个条件来过滤只有成功。并像您一样使用 Window Functions

select spacecraft.* , max(started) over (partition by spacecraft.id)  
from spacecraft 
    left outer join 
    launch 
    on spacecraft.id = spacecraft_id
where success

SQL FIDDLE

这是我的解决方案。

SELECT s.id, s.name, l.last_started
FROM spacecraft AS s
INNER JOIN (SELECT spacecraft_id, MAX(started) AS last_started FROM launch WHERE success GROUP BY spacecraft_id) AS l
ON s.id = l.spacecraft_id

http://sqlfiddle.com/#!15/45618/50

假设您想要结果中 spacecraft 的所有列,加上最新的 launch 和同一行的 success

每个航天器的几次发射速度更快:

SELECT s.*, l.last_launch, l.success
FROM   spacecraft s
LEFT   JOIN (
   SELECT DISTINCT ON (spacecraft_id)
          spacecraft_id, started AS last_launch, success
   FROM   launch
   ORDER  BY spacecraft_id, started DESC
   ) l ON l.spacecraft_id = s.id;

每个航天器的多次发射速度更快:

SELECT s.*, l.last_launch, l.success
FROM   spacecraft s
LEFT   JOIN LATERAL (
   SELECT started AS last_launch, success
   FROM   launch
   WHERE  spacecraft_id = s.id
   ORDER  BY started DESC
   LIMIT  1
   ) l ON true;

LATERAL 需要 Postgres 9.3+。
LEFT JOIN 包括没有发射的航天器。否则使用 JOIN.

快速 中任一查询的基本要素是 (spacecraft_id, started) 上的多列索引。对于这个特定的查询,success 到索引以允许仅索引扫描将是有益的:

CREATE INDEX launch_foo_idx ON launch (spacecraft_id, started DESC, success);

SQL Fiddle.

详细解释:

  • Optimize GROUP BY query to retrieve latest record per user
  • Select first row in each GROUP BY group?