【问题标题】:GroupingError: ERROR: column " " must appear in the GROUP BY clause or be used in an aggregate functionGroupingError:错误:列“”必须出现在 GROUP BY 子句中或在聚合函数中使用
【发布时间】:2015-06-22 00:20:27
【问题描述】:

我正在尝试创建一个已离开 cmets 的独特患者的列表。代码字很好,直到我上传到它在 postgresql 中不起作用的 heroku。

这是我创建列表的 Ruby .erb 代码:

<% @comments.group(:patient_id).each_with_index do |comment, index| %>
    <div class="profile-post color-one">
       <span class="profile-post-numb"><%= index+1 %></span>
        <div class="profile-post-in">
            <h3 class="heading-xs"><a><%= link_to "#{comment.patient.first_name} #{comment.patient.last_name}", comment_path(comment) %></a></h3>
            <p>Lastest comment from <%= time_ago_in_words(comment.created_at) %> ago<i class="pull-right"><%= link_to "Edit", edit_comment_path(comment) %> <%= link_to "Delete", comment_path(comment), method: :delete, data: {confirm: 'Are you sure you want to delete'} %></i></p>
        </div>
    </div>
<% end %>

@cmets 在控制器中定义为:

def index
  @comments = current_clinician.comments.order("created_at desc")
end

heroku 日志给我这个错误信息:

PG::GroupingError: ERROR:  column "comments.id" must appear in the GROUP BY clause or be used in an aggregate function

LINE 1: SELECT "comments".* FROM "comments"  WHERE  comments"."clini...
               ^
SELECT "comments".* *FROM "comments"  WHERE "comments"."clinician_id" = $1 GROUP BY patient_id  ORDER BY created_at desc

我已经尝试过其他 SO 问题的解决方案,例如 20942477。其中说我应该将字段 cmets.id 添加到我的组子句中:

<% @comments.group(:patient_id, :"comments.id").each_with_index do |comment, index| %>

这消除了 heroku 上的错误,但违背了 group 命令的目的 - 它不再只显示独特的患者,而是列出所有患者。

我也尝试了1780893 的解决方案。其中说我应该更改 ORDER BY:

@comments = current_clinician.comments.order("substring(created_at,1.8) desc")

这在本地给出了这个错误:

SQLite3::SQLException:没有这样的函数:子字符串:SELECT "cmets".* FROM "cmets" WHERE "cmets"."clinician_id" = ?命令 BY substring(created_at,1.8) desc

我意识到这是一个常见问题,我对 SQL 缺乏经验,因此无法获取代码,因此它可以在我的开发和生产环境中运行。我在 SO 上阅读的答案不是使用 Ruby 来获取 SQL 并超过我的经验水平。

【问题讨论】:

  • 错误告诉你你正在尝试做的事情不能以这种方式完成。在此查询中,每个不同的患者 ID 仅返回一行。此患者 ID 可能有多个评论行。假设有 10 个 cmets 具有相同的 patient_id - 如果我们选择一个我们没有分组的列(例如它的 id),那么这个值应该来自 10 个中的哪一行?这是模棱两可的,所以 SQL 不允许你这样做。您只能使用要分组的列或聚合分组行的函数的输出,例如 COUNT 或 SUM。

标签: ruby-on-rails ruby postgresql heroku group-by


【解决方案1】:

您不能在 Postgres 中将 SELECT *GROUP BY some_column 结合使用(除非 some_column 是 PK),因为这是矛盾的。所有非聚合列(在聚合函数之外的SELECTHAVINGORDER BY 子句中使用)必须在GROUP BY 列表中——其中主键列可以替换表的所有列。否则未定义从聚合集中选择哪个值。

Per documentation:

当存在GROUP BY 或存在任何聚合函数时,它 对于 SELECT 列表表达式引用未分组的无效 聚合函数内或未分组列除外的列 在功能上取决于分组列,因为会有 否则为一个未分组的返回多个可能的值 柱子。如果分组列(或 子集)是包含表的主键 未分组的列。

已知某个其他 RDBMS 在这里玩弄脏了,并允许这样做并选择任意值...

您似乎想要一个已发表评论的独特患者列表,每个都有最新评论。 Postgres 中最简单的方法是使用DISTINCT ON:

SELECT DISTINCT ON (patient_id) *
FROM   comments
WHERE  clinician_id = $1
ORDER  BY patient_id, created_at DESC NULLS LAST;

但这不会与 SQLite 一起使用 - 它不应该在循环中开始:

NULLS LAST 仅在 created_at 可以为 NULL 时才相关:

DISTINCT ON的详细信息:

【讨论】:

  • 感谢 Erwin,这是一个非常有帮助的答案。我已切换到在本地使用 PostreSQL,DISTINCT ON 给了我一个独特患者的列表:@comments.order("patient_id, created_at DESC").select('ON (patient_id) *').uniq.each_with_index do |comment, index| 患者现在按照他们在我的 seed.rb 文件中创建的顺序排序 - 所以按照他们的创建顺序.您对如何通过他们最新评论的created_at 订购它们有什么建议吗?
  • @Skiapex:将此查询包装到具有不同 ORDER BY 的外部查询中。以下是详细说明:stackoverflow.com/questions/24619117/…
猜你喜欢
  • 2014-01-23
  • 1970-01-01
  • 2017-02-28
  • 1970-01-01
  • 2014-12-26
  • 2020-06-11
  • 2020-11-04
  • 2016-09-16
相关资源
最近更新 更多