And*_*ndy 45 ruby postgresql ruby-on-rails distinct ruby-on-rails-3
ActionView :: Template :: Error(PG ::错误:错误:对于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') %>
Run Code Online (Sandbox Code Playgroud)
Adr*_*oKF 70
我知道这是一个相当古老的问题,但我只是通过一个小例子来帮助我理解为什么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
Run Code Online (Sandbox Code Playgroud)
现在,您想要获取由各自的start_times排序的不同event_ids的列表.但应该1去哪里?它应该是第一个,因为一个元组在1970年1月1日开始,还是应该因为2013年8月21日而持续?
由于数据库系统无法为您做出决定,并且查询的语法不能依赖于它可能正在操作的实际数据(假设event_id是唯一的),因此我们仅限于按SELECT子句中的列进行排序.
至于实际的问题 - 马修的答案的另一种选择是使用类似MIN或MAX用于排序的聚合函数:
SELECT event_id
FROM Rsvp
GROUP BY event_id
ORDER BY MIN(start_time)
Run Code Online (Sandbox Code Playgroud)
显式分组和聚合start_time允许数据库提出结果元组的明确排序.但请注意,在这种情况下,可读性肯定是一个问题;)
Mat*_*ood 57
ORDER BY子句只能在应用DISTINCT 后应用.由于DISTINCT操作仅考虑SELECT语句中的字段,因此这些字段可以在ORDER BY中使用.
从逻辑上讲,如果您只想要一个独特的event_id值列表,它们发生的顺序应该是无关紧要的.如果顺序很重要,那么您应该将start_time添加到SELECT列表中,以便订单具有上下文.
另外,这两个SELECT子句不等价,所以要小心:
SELECT DISTINCT(event_id, start_time) FROM ...
SELECT DISTINCT event_id, start_time FROM ...
Run Code Online (Sandbox Code Playgroud)
第二个是你想要的形式.第一个将返回一系列记录,数据表示为ROW构造(单个列,里面有元组).第二个将返回正常的数据输出列.它仅在单列情况下按预期工作,其中ROW结构减少,因为它只是一列.
我认为,只有理解了SQL 中操作的逻辑顺序,才能真正理解and(或就此而言)之间关系DISTINCTORDER BY的混乱。它与操作的句法顺序不同,而操作的句法顺序是造成混乱的主要根源。GROUP BY
在这个例子中,鉴于其语法上的接近性,它看起来好像与DISTINCT相关SELECT,但它实际上是一个在(投影)之后应用的运算符。 SELECT由于操作(删除重复行)的性质,行的所有未投影内容在操作(包括该子句)之后DISTINCT不再可用。根据运算的逻辑顺序(简化):DISTINCTORDER BY
FROM(生成所有可能的列引用)WHERE(可以使用来自 的所有列引用FROM)SELECT(可以使用 中的所有列引用FROM,并创建新表达式,并为其指定别名)DISTINCT(对由 投影的元组进行操作SELECT)ORDER BY(取决于 的存在DISTINCT,可以对由 投影的元组进行操作SELECT,并且如果DISTINCT不存在*也许(取决于方言)也对其他表达式进行操作)DISTINCT和呢?ORDER BY事实上,如果没有DISTINCT,ORDER BY也可以访问(在某些方言中)尚未投影的内容,这可能有点奇怪,但确实有用。例如,这有效:
WITH emp (id, fname, name) AS (
VALUES (1, 'A', 'A'),
(2, 'C', 'A'),
(3, 'B', 'B')
)
SELECT id
FROM emp
ORDER BY fname DESC
Run Code Online (Sandbox Code Playgroud)
dbfiddle 在这里。生产
id
--
2
3
1
Run Code Online (Sandbox Code Playgroud)
当您添加DISTINCT. 这不再有效:
WITH emp (id, fname, name) AS (
VALUES (1, 'A', 'A'),
(2, 'C', 'A'),
(3, 'B', 'B')
)
SELECT DISTINCT name
FROM emp
ORDER BY fname DESC
Run Code Online (Sandbox Code Playgroud)
dbfiddle 在这里。错误是:
错误:对于 SELECT DISTINCT,ORDER BY 表达式必须出现在选择列表第 8 行:ORDER BY fname DESC
因为fname你会赋予什么价值name = A?A或者C?答案将决定您是否会得到A,B结果或B, A。无法决定。
DISTINCT ON现在,正如上面链接的文章中提到的,PostgreSQL 支持一个例外,这有时会很有用:(DISTINCT ON另请参阅此类问题):
WITH emp (id, fname, name) AS (
VALUES (1, 'A', 'A'),
(2, 'C', 'A'),
(3, 'B', 'B')
)
SELECT DISTINCT ON (name) id, fname, name
FROM emp
ORDER BY name, fname, id
Run Code Online (Sandbox Code Playgroud)
dbfiddle 在这里,产生:
id |fname|name
---|-----|----
1 |A |A
3 |B |B
Run Code Online (Sandbox Code Playgroud)
此查询允许仅生成 的不同值name,然后对每个重复行取给定子句的第一个值ORDER BY,这使得每个不同组的选择明确。这可以在其他 RDBMS 中使用窗口函数进行模拟。
| 归档时间: |
|
| 查看次数: |
51393 次 |
| 最近记录: |