2016-12-30 5 views
0

私はPostgresを初めて使用していましたが、私は以前はMySQLを使用していました。MAX値の行から他のフィールドを選択する方法

私の問題はシンプルですが、MySQLでは決して起こりません。 t1は私のメインテーブルであり、t2はステータスと呼ばれるフィールドに発生した更新履歴をt1という名前で保持しています。したがって、t1のエントリがステータスフィールドを変更するたびに、新しいレコードが現在のタイムスタンプと新しいステータス値でt2に追加されます。

t1の特定のエントリの最新ステータスとタイムスタンプを取得したいとします。例えば、IDがのものです。次のクエリで最新のタイムスタンプを取得できます。

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集合体から1行を返すので、selectに存在する場合は、その特定のものから他のフィールドを返します。とにかくPostgreSQLでそれを行うには? –

+0

正しいプライマリキーと外部キーを定義すると、Postgresは十分にスマートになります。私の答えを参照してください –

答えて

0

は、それが無効なSQLですので、あなたのクエリはPostgresではによって拒否されたサブクエリ選択最大(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は異なるID(table_1_id)の情報を保持します – MtwStark

+0

私はまだ私が逃したものを得ることはありません。 join節に条件を追加しました。それについて何が間違っていますか?結合は以前と同じように機能しますが、すべてのタイムスタンプに参加するのではなく、tme max(creation_timestamp) – cybernetic87

+0

を選択するだけです。select max()が間違っていて、table_1_idでグループ化する必要があります。 – MtwStark

2

を使用しましょう。この問題はMySQLにも存在しています。MySQLは無効なグループを拒否するのではなく、ランダムな値を返すことを選択しているので、これまで運が良かったです(thisまたはthis)。

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例:あなたはのtable_1に最新のステータスを持っている必要がありhttp://sqlfiddle.com/#!15/7cfc8/1

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 
関連する問題