ActionView :: Template :: Error(PG :: Error:ERROR:SELECT DISTINCTの場合、ORDER BY式は選択リストに表示する必要があります
私はイベントのウェブサイトを作成しており、レンダリングされたrsvpsをイベントの開始時間で並べ替えようとしています。 RSVPSがたくさんあるので、それらを個別にグループ化していますが、過去数日間、PGにこのエラーが表示されることなく結果を並べ替えるのに苦労していました。このトピックに関する以前の質問のいくつかを見てきましたが、まだかなり迷っています。これを機能させるにはどうすればよいですか?どうもありがとうございます!
@rsvps = Rsvp.where(:voter_id => current_user.following.collect {|f| f["id"]}, :status => 'going').where("start_time > ? AND start_time < ?", Time.now, Time.now + 1.month).order("count_all desc").count(:group => :event_id).collect { |f| f[0] }
<%= render :partial => 'rsvps/rsvp', :collection => Rsvp.where(:event_id => @rsvps).select("DISTINCT(event_id)").order('start_time asc') %>
ORDER BY句を適用できるのは、後 DISTINCTが適用された後のみです。 DISTINCT操作ではSELECTステートメントのフィールドのみが考慮されるため、ORDER BYで使用できるフィールドはこれらのみです。
論理的には、event_id値の個別のリストが必要な場合、それらが発生する順序は関係ありません。順序が重要な場合は、順序のコンテキストが存在するように、start_timeをSELECTリストに追加する必要があります。
また、これら2つのSELECT句は同等ではないため、注意してください。
SELECT DISTINCT(event_id, start_time) FROM ...
SELECT DISTINCT event_id, start_time FROM ...
2番目は、必要なフォームです。 1つ目は、ROWコンストラクト(内部にTupleを持つ単一の列)として表されるデータを含む一連のレコードを返します。 2番目は、データ出力の通常の列を返します。 ROW構造が1列のみであるため、ROW構造が削減される単一列の場合にのみ期待どおりに機能します。
私はこれがかなり古い質問であることを知っていますが、PostgresがSELECT DISTINCT/ORDER BY列にこの一見奇妙な制限を持っている理由を理解するのに役立った私の頭の中の小さな例を通過しました。
Rsvpテーブルに次のデータがあると想像してください。
event_id | start_time
----------+------------------------
0 | Mar 17, 2013 12:00:00
1 | Jan 1, 1970 00:00:00
1 | Aug 21, 2013 16:30:00
2 | Jun 9, 2012 08:45:00
次に、それぞれのstart_timesの順序で並べられた個別のevent_idのリストを取得します。しかし、1
はどこに行くべきでしょうか?タプルは1970年1月1日に開始されるため、最初に来るべきですか、それとも2013年8月21日に続く必要がありますか?
データベースシステムはその決定を下すことができず、クエリの構文は操作対象の実際のデータに依存できないため(event_id
が一意であると仮定)、列による順序のみに制限されます。 SELECT
句から。
実際の質問に関しては-Matthewの答えに代わるものは、ソートにMIN
やMAX
のような集約関数を使用することです:
SELECT event_id
FROM Rsvp
GROUP BY event_id
ORDER BY MIN(start_time)
start_time
の明示的なグループ化と集約により、データベースは結果タプルの明確な順序付けを行うことができます。ただし、この場合、可読性は間違いなく問題です;)
なぜなら、start_time列を使用しているため、 PostgreSQLのウィンドウ関数 の1つであるrow_number()を使用して、
start_timeの順序、最初のstart_timeで行の値を期待している場合
(SELECT event_id、ROW_NUMBER()OVER(PARTITION BY event_id ORDER BY start_time)AS first_row FROM Rsvp)からevent_idを選択します。first_row= 1
最後のstart_timeで行の値を期待している場合、start_timeの逆順
(SELECT event_id、ROW_NUMBER()OVER(PARTITION BY event_id ORDER BY start_time desc)AS last_row FROM Rsvp)からevent_idを選択しますlast_row = 1
要件に応じて異なる Window Function を使用することもできます。