如何从具有MAX值的行中选择其他字段

时间:2016-12-30 11:06:52

标签: sql postgresql greatest-n-per-group

我是Postgres的新手,我曾经使用过MySQL。

我的问题很简单,在MySQL中也不会发生。 t1是我的主表,t2包含t1状态中t1字段的更新历史记录。因此,只要t2中的条目更改其状态字段,就会使用当前时间戳和新状态值将新记录添加到t1

现在我想获取SELECT t1.id, t1.message, MAX(t2.creation_timestamp) FROM table_1 t1 LEFT JOIN table_2 t2 ON t1.id = t2.table_1_id WHERE t1.id = 1271 GROUP BY t1.id,t1.message 中特定条目的最新状态和时间戳,例如id 1271 。我可以通过以下查询获取最新的时间戳。

SELECT
  t1.id,
  t1.message,
  t2.status,
  MAX(t2.creation_timestamp)
FROM table_1 t1
LEFT JOIN table_2 t2 ON t1.id = t2.table_1_id
WHERE t1.id = 1271
GROUP BY t1.id,t1.message

但是当我尝试使用MAX时间戳获取该特定行的状态时。

ERROR: column "t2.status" must appear in the GROUP BY clause or be used in an aggregate function

我收到以下错误:

{{1}}

如何使用MAX时间戳获取记录的状态?

3 个答案:

答案 0 :(得分:2)

您的查询被Postgres拒绝,因为它是无效的SQL。 MySQL中也存在这个问题,到目前为止你很幸运,因为MySQL选择返回随机值而不是拒绝无效组(你可能想要阅读thisthis以获取有关MySQL的详细信息实现)

Postgres中最有效的解决方案是使用distinct on ()

SELECT distinct on (t1.id)
       t1.id,
       t1.message,
       t2.status,
       t2.creation_timestamp
FROM table_1 t1
  LEFT JOIN table_2 t2 ON t1.id = t2.table_1_id
WHERE t1.id = 1271
ORDER BY t1.id, t2.creation_timestamp DESC;

但是,如果将 id定义为table_1的主键,并且两个表之间存在正确的外键关系,则Postgres 接受部分组,因为它知道id是唯一的。

psql (9.6.1)
Type "help" for help.

postgres=> create table table_1 (id integer primary key, message text);
CREATE TABLE
postgres=> create table table_2 (table_1_id integer references table_1, status text, creation_timestamp timestamp);
CREATE TABLE

postgres=> insert into table_1
postgres-> values
postgres-> (1271, 'one'),
postgres-> (1272, 'two'),
postgres-> (1273, 'three');
INSERT 0 3

postgres=> insert into table_2
postgres-> values
postgres-> (1271, 'active', timestamp '2016-12-30 10:00:00'),
postgres-> (1271, 'active', timestamp '2016-12-30 11:00:00'),
postgres-> (1271, 'active', timestamp '2016-12-30 12:00:00'),
postgres-> (1272, 'active', timestamp '2016-12-30 11:00:00'),
postgres-> (1272, 'active', timestamp '2016-12-30 12:00:00'),
postgres-> (1273, 'active', timestamp '2016-12-30 13:00:00'),
postgres-> (1273, 'active', timestamp '2016-12-30 13:00:00');
INSERT 0 7

postgres=> SELECT
postgres->   t1.id,
postgres->   t1.message,
postgres->   MAX(t2.creation_timestamp)
postgres-> FROM table_1 t1
postgres-> LEFT JOIN table_2 t2 ON t1.id = t2.table_1_id
postgres-> WHERE t1.id = 1271
postgres-> GROUP BY t1.id
postgres-> ;
  id  | message |         max
------+---------+---------------------
 1271 | one     | 2016-12-30 12:00:00
(1 row)

SQLFiddle示例:http://sqlfiddle.com/#!15/7cfc8/1

答案 1 :(得分:1)

你应该拥有table_1的最新状态,你不应该从table_2中获取它,你只需要最新的时间戳

SELECT 
    t1.id, 
    t1.message, 
    t1.status, 
    tmax.creation_timestamp
from table_1 t1
left join (
    select table_1_id, MAX(creation_timestamp) creation_timestamp 
    from table_2 
    group by table_1_id
) tmax on tmax.table_1_id = t1.id
WHERE t1.id = 1271

答案 2 :(得分:0)

使用子查询选择加入max(creation_timestamp)

SELECT
 t1.id,
 t1.message,
 t2.status,
 t2.creation_timestamp
FROM table_1 t1
LEFT JOIN table_2 t2 ON t1.id = t2.table_1_id 
and t2.creation_timestamp = (SELECT MAX(creation_timestamp) 
from table_2 t3 where t1.id = t3.table_1_id ) 
WHERE t1.id = 1271