ActionView::模板::错误(PG::错误:错误:对于SELECT DISTINCT,ORDER BY表达式必须出现在选择列表中
我正在创建一个事件网站,我试图排序的事件的开始时间呈现的回复。有很多的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') %>
6条答案
按热度按时间rqdpfwrv1#
我知道这是一个相当老的问题,但我刚刚在脑海中经历了一个小例子,它帮助我理解了为什么Postgres对SELECT DISTINCT / ORDER BY列有这个看似奇怪的限制。
假设你的Rsvp表中有以下数据:
现在,您需要获取一个不同event_id的列表,并按照它们各自的start_time进行排序。但是
1
应该去哪里呢?它应该排在第一位,因为一元组从1970年1月1日开始,还是应该排在最后,因为2013年8月21日?由于数据库系统不能为您做出决定,并且查询的语法不能依赖于它可能操作的实际数据(假设
event_id
是唯一的),因此我们仅限于按SELECT
子句中的列进行排序。至于实际的问题-Matthew的答案的替代方案是使用
MIN
或MAX
这样的聚合函数进行排序:start_time
上的显式分组和聚合允许数据库对结果元组进行明确的排序。但是请注意,在这种情况下,可读性肯定是一个问题;)lbsnaicq2#
ORDER BY子句只能在 * DISTINCT已应用 * 之后应用。由于DISTINCT操作只考虑SELECT语句中的字段,因此ORDER BY中只能使用这些字段。
从逻辑上讲,如果您只是想要一个不同的event_id值列表,那么它们出现的顺序应该是无关紧要的。如果顺序很重要,那么您应该将start_time添加到SELECT列表中,以便有顺序的上下文。
另外,这两个SELECT子句并不等价,所以要小心:
第二种是你想要的形式。第一个将返回一系列记录,其中数据表示为ROW结构(其中包含元组的单个列)。第二个将返回正常列的数据输出。它仅在单列情况下按预期工作,其中ROW构造被减少,因为它只有单列。
rslzwgfq3#
语法与逻辑操作顺序
我认为,围绕relationship between
DISTINCT
andORDER BY
(或GROUP BY
,就此而言)的混乱,只有在理解logical order of operations in SQL的情况下才能真正理解。它不同于操作的句法顺序,这是混淆的主要来源。在这个例子中,
DISTINCT
看起来好像与SELECT
相关,因为它的语法很接近,但它实际上是一个在SELECT
(投影)之后应用的运算符。由于DISTINCT
所做的事情(删除重复行)的性质,一行中所有未投影的内容 * 在 *DISTINCT
操作(包括ORDER BY
子句)之后都不再可用。根据logical order of operations (simplified):FROM
(生成所有可能的列引用)WHERE
(可以使用来自FROM
的所有列引用)SELECT
(可以使用FROM
中的所有列引用,并创建新的表达式和别名)DISTINCT
(对SELECT
投影的元组进行操作)ORDER BY
(取决于DISTINCT
的存在,可以对SELECT
投影的元组进行操作,如果DISTINCT
不存在 * 也许(取决于方言)也可以对其他表达式进行操作)DISTINCT
和ORDER BY
呢事实上,没有
DISTINCT
,ORDER BY
也可以访问(在某些方言中)没有被投影的东西可能有点奇怪,当然是有用的。例如,这起作用:dbfiddle here.生产
添加
DISTINCT
时,此情况会发生变化。这不再起作用:dbfiddle here。错误为:
错误:对于SELECT DISTINCT,ORDER BY表达式必须出现在选择列表行8中:订单由fname指定
因为
fname
的值是什么?A
还是C
?答案将决定结果是得到A
、B
还是B
、A
。这是无法决定的。PostgreSQL
DISTINCT ON
现在,正如above linked article中提到的,PostgreSQL支持一个例外,这偶尔会很有用:
DISTINCT ON
(另见questions like these):dbfiddle here,产生:
此查询允许仅生成
name
的不同值,然后在每个重复行中,取给定ORDER BY
子句的第一个值,这使得每个不同组的选择是明确的。This can be emulated in other RDBMS using window functions。neekobn84#
因为使用的是start_time列,所以可以使用row_number(),它是Window Functions of PostgreSQL中的一个,并将其堆叠在
Select event_id from(SELECT event_id,ROW_NUMBER()OVER(PARTITION BY event_id ORDER BY start_time)AS first_row FROM Rsvp)其中first_row = 1
选择event_id from(SELECT event_id,ROW_NUMBER()OVER(PARTITION BY event_id ORDER BY start_time desc)AS last_row FROM Rsvp)其中last_row = 1
您也可以根据需要使用不同的Window Function。
r55awzrz5#
这个GitHub的答案给了我一个我在这里发布的其他答案中找不到的洞察力。
总之,您需要与SELECT语句中的ORDER BY语句具有相同的逻辑。
在给出的示例中,他们使用CASE语句来定制订单。
然而,在示例中,它们有两次CASE语句,这是不必要的,SQL可以简化为:
假设这是Rails中的一个模型,则示例可以写成:
如果排序顺序上不需要自定义名称,ActiveRecord会将其命名为case,这也可以用于排序
suzh9iv86#
我可以通过在select中添加一列,然后在该列上使用
ORDER BY
来解决这个错误。我有SELECT DISTINCT concat(dl.FirstName, concat(' ', dl.LastName)) as displayName, ...
,我想ORDER BY
姓(就像一个人)。我尝试了我能想到的在SELECT
中添加ORDER BY
的每一种排列,但有效的是添加, dl.LastName as lastName
,然后在查询的末尾添加ORDER BY lastName ASC
,就像在一个更典型的查询中一样。最后我增加了一列,但在我的应用程序中很容易忽略它。