2016-12-30 2 views
0

Я новичок в Postgres, я работал с MySQL.Как выбрать другие поля из строки с MAX значением

Моя проблема проста, она также никогда не бывает в 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 

Но когда я пытаюсь также получить статус этой конкретной строки с меткой времени MAX.

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 

Я получаю следующее сообщение об ошибке:

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

Как я могу получить статус записи с меткой времени MAX?

+0

Или, может быть, MySQL достаточно умен, чтобы понять, что, поскольку запрос вернет одну строку из агрегата MAX, тогда он вернет другие поля из этого конкретного, если они существуют в select. В любом случае, как это сделать в Postgresql? –

+0

Postgres был бы достаточно умен, если вы определяете правильные первичные и внешние ключи. См. Мой ответ –

ответ

0

Регистрация с помощью подзапросов Выбор макс (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 
+0

вы пропустили, что table_2 хранит информацию о разных идентификаторах (table_1_id) – MtwStark

+0

Я до сих пор не получаю то, что пропустил. Я добавил дополнительные условия к предложению join. Что в этом плохого?Присоединяйся к работам, пока он работал, но вместо того, чтобы присоединяться ко всем временным меткам, он объединяет только тот, который имеет tme max (creation_timestamp) – cybernetic87

+0

. Select max() неверен, должен быть сгруппирован по таблице_1_id – MtwStark

2

Ваш запрос отвергается Postgres, потому что это недопустимый SQL. Проблема существует в MySQL, а также, вы просто повезло, до сих пор, потому что MySQL выбирает вернуть случайные значения, а затем отвергая недопустимый группу, (вы можете прочитать this или this подробную информацию о реализации 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

вы должны иметь последний статус на 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 
Смежные вопросы