PostgreSQLでは、すべてのユーザーを一度に取得して、日付順に並べたいと思っています。
これは私の質問です:
_SELECT id, useridx, isread, message, date
FROM messages
WHERE isread = 1
GROUP BY useridx
ORDER BY date DESC
_
これはサンプルデータ:
_------------------------------------------------------
+ id | useridx | isread | messsage | date +
------------------------------------------------------
1 | 1 | 0 | Hello | 2012-01-01
2 | 2 | 1 | Hi | 2012-01-02
3 | 3 | 1 | Test | 2012-01-03
4 | 3 | 0 | My Msg | 2012-01-04
5 | 4 | 1 | sadasd | 2012-01-05
6 | 4 | 1 | sdfsdfd | 2012-01-06
7 | 4 | 0 | sdfsdfsd | 2012-01-07
8 | 5 | 0 | 5345634 | 2012-01-08
9 | 6 | 0 | sdfdfsd | 2012-01-09
10 | 7 | 0 | sdfsdfsf | 2012-01-10
------------------------------------------------------
_
さて、私がやりたいのは、useridxを介してグループ化し、日付で並べ替えて、このテーブルをフェッチすることです。
期待される結果:
_------------------------------------------------------
+ id | useridx | isread | messsage | date +
------------------------------------------------------
6 | 4 | 1 | sdfsdfd | 2012-01-06
3 | 3 | 1 | Test | 2012-01-03
2 | 2 | 1 | Hi | 2012-01-02
------------------------------------------------------
_
実際の結果
_ERROR: column "messages.date" must appear in the GROUP BY clause or be used in an aggregate function
_
私も日付をグループ化したくありません。 useridxでグループ化し、日付DESCで並べ替えたいだけです。
どんな助け/アイデアも大歓迎です!
注:Distinctも試しました。私のニーズに合わないか、間違ってやりました。
私は非常に混乱して立ち往生しています _DISTINCT ON
_メソッドとrank()
メソッドの間です。
結論:ここで同じ問題を抱えている人は、これを答えとして読むことができます。 @kgrittnと@muの両方が短すぎます。答えは正しいです。私は自分のプロジェクトで回答とスキーマの両方を使い続け、やがてどちらが最良かを理解することができます-私は推測します-。それで、それらの1つを選んで、あなたの仕事を続けてください。あなたは大丈夫です。
最終更新:DistinctOnが一部のIDを結果から除外する場合があります。 id列があり、同じ6行があるとします。したがって、結果とは区別されますが、rank()は結果になります。 したがって、rank()を使用してください!
rank()
window function を使用して、各useridx
グループ内の結果を並べ替え、ランク付けされた結果を派生テーブルでラップして最初のグループをはがします。 :
select id, useridx, isread, message, date
from (
select id, useridx, isread, message, date,
rank() over (partition by useridx order by date desc) as r
from messages
where isread = 1
) as dt
where r = 1
これにより、サンプルのid
2、3、および6の行が得られます。同じ日にover
ごとに複数のメッセージがある場合に一貫して選択できるように、useridx
にセカンダリソートキーを追加することをお勧めします。
ウィンドウ関数を使用するには、少なくともPostgreSQL 8.4(AFAIK)が必要です。
MySQLとは異なり、PostgreSQLは、集約されたクエリで集約されていない列のランダムデータを表示しません。
解決策はエラーメッセージにあります
ERROR: column "messages.date" must appear in the GROUP BY clause or be used in an aggregate function
つまり、この列を選択するときは、「messages.date」列でGROUP BYするか、MIN()やMAX()などの集計関数を使用する必要があります。
例:
SELECT MIN(id), useridx, isread, message, MAX(date)
FROM messages WHERE isread = 1
GROUP BY useridx, isread, message
ORDER BY MAX(date) DESC
もう1つのオプションは、SELECT DISTINCT ON
を使用することです(これは、単純なSELECT DISTINCT
とは大きく異なります)。
SELECT *
FROM (SELECT DISTINCT ON (useridx)
id, useridx, isread, message, date
FROM messages
WHERE isread = 1
ORDER BY useridx, date DESC) x
ORDER BY date DESC;
場合によっては、これは他のアプローチよりも拡張性が高くなります。
数年後ですが、FROMサブクエリで注文することはできません。
SELECT m.id, m.useridx, m.isread, m.message, m.date
FROM (
SELECT m2.id, m2.useridx, m2.isread, m2.message, m2.date
FROM message m2
ORDER BY m2.id ASC, m2.date DESC
) m
WHERE isread = 1
GROUP BY useridx
これはPostgreSQL9.2で機能します
結果を集計しています。
これは、ユーザー_3
_の2行ではなく、1行だけになることを意味します。ただし、集約された行にはid
、message
、isread
列も選択します。 PostgreSQLはこのデータをどのように配信することになっていますか?可能な値のmax()
である必要がありますか?多分min()
?
最新のメッセージに関するデータが必要だと思います。このクエリを試してください:
_SELECT id, useridx, isread, message, date FROM messages
WHERE isread = 1 AND (useridx, date) IN
(SELECT useridx, max(date) FROM messages WHERE isread = 1 GROUP BY useridx);
_