我正在使用mysql开发我的应用程序,但我使用Heroku来部署它并被迫使用PG。
我对以下声明有疑问:
<% current_user_savings = Saving.where{user_id == my{current_user}} %>
<% @latest_savings = Saving.where{product_id.not_in(current_user_savings.select{product_id})}.group{product_id} %>
因此它可以在我的计算机上运行,但在部署到heroku时,我遇到以下问题:
ActionView::Template::Error (PGError: ERROR: column "savings.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT "savings".* FROM "savings" WHERE "savings"."product_...
SELECT "savings".* FROM "savings" WHERE "savings"."product_id" NOT IN (SELECT "savings"."product_id" FROM "savings" WHERE "savings"."user_id" = 1) GROUP BY "savings"."product_id"):
我真的不知道如何修复它并让它在heroku上运行。
请求的Gemfile: 来源'https://rubygems.org'
ruby '1.9.3'
gem 'rails', '3.2.7'
gem 'compass_twitter_bootstrap', '2.0.3'
gem 'bcrypt-ruby', '3.0.1'
gem 'faker', '1.0.1'
gem 'will_paginate', '3.0.3'
gem 'bootstrap-will_paginate', '0.0.6'
gem 'omniauth-facebook', '1.4.0'
gem 'railroady'
gem 'devise', '2.1.2'
gem 'devise_invitable'
gem 'simple_form'
gem "mongoid", "~> 3.0.0"
gem 'thin'
gem 'best_in_place'
gem "jquery-fileupload-rails"
gem 'paperclip'
gem "squeel"
gem 'client_side_validations'
gem 'wicked'
gem 'koala'
gem 'aws-sdk'
gem 'bson_ext'
group :development, :test do
gem 'sqlite3'
end
group :development, :test do
gem 'annotate', '2.5.0'
end
group :test, :development do
gem 'rspec-rails'
end
group :assets do
gem 'sass-rails', '~> 3.2.3'
gem 'compass-rails', '1.0.3'
gem 'coffee-rails', '~> 3.2.1'
gem 'uglifier', '>= 1.0.3'
end
gem 'jquery-rails'
gem 'jquery-ui-rails'
group :test do
gem 'capybara'
gem 'factory_girl_rails'
end
group :production do
gem 'pg', '0.12.2'
end
答案 0 :(得分:1)
我认为这些代码中的一些属于范围或至少属于您的控制器。但除此之外,你可以发布你的Gemfile吗?
在我看来,最好的做法是在开发中使用相同的数据库和ORM。你试过在本地运行PG吗?
看起来这里可能会发生一些让你很难过的事情,首先让PG在你的开发机器上本地运行并更新你的databases.yml
以便重合。
其次,你也使用MongoBD吗?如果您不再使用它,可能会从包中删除它。
我稍微清理了你的Gemfile以使其更容易阅读,但我建议将宝石分组,以更好地代表宝石在项目中的角色,我喜欢记录每个宝石,以便明白是什么通常情况下,rails应用程序倾向于以巨大的Gemfile结束,这使得拾取其他人的项目变得非常困难:
source 'https://rubygems.org'
ruby '1.9.3'
gem 'rails', '3.2.7'
gem 'compass_twitter_bootstrap', '2.0.3'
gem 'bcrypt-ruby', '3.0.1'
gem 'faker', '1.0.1'
gem 'will_paginate', '3.0.3'
gem 'bootstrap-will_paginate', '0.0.6'
gem 'omniauth-facebook', '1.4.0'
gem 'railroady'
gem 'devise', '2.1.2'
gem 'devise_invitable'
gem 'simple_form'
gem 'best_in_place'
gem "jquery-fileupload-rails"
gem 'paperclip'
gem "squeel"
gem 'client_side_validations'
gem 'wicked'
gem 'koala'
gem 'aws-sdk'
gem 'pg', '0.12.2'
gem 'jquery-rails'
gem 'jquery-ui-rails'
group :development, :test do
gem 'annotate', '2.5.0'
gem 'rspec-rails'
end
group :test do
gem 'capybara'
gem 'factory_girl_rails'
end
group :assets do
gem 'sass-rails', '~> 3.2.3'
gem 'compass-rails', '1.0.3'
gem 'coffee-rails', '~> 3.2.1'
gem 'uglifier', '>= 1.0.3'
end
最后,请查看您的application.rb
,并确保ActiveRecord可用,看起来似乎必须这样,但看一看,您可能在顶部附近的某处有require "rails/all"
。
答案 1 :(得分:1)
GROUP BY
is a known pain point when users are migrating from MySQL to PostgreSQL
正如@rs所说,你的SQL有些问题。
假设savings.product_id
是主键,因为这是该查询唯一的正确方法,它依赖于数据库知道主键分组隐式地将所有字段分组,因为主键是唯一的。
MySQL不知道,它只是继续并选择它为每个字段看到的第一个结果。在这种情况下,这是正确的,因为您按主键进行分组,但在其他情况下很容易产生不可预测的结果。
PostgreSQL 9.0及以下版本不认识到按主键分组意味着您已对所有字段进行分组,尽管SQL-99标准要求它这样做。这些版本要求您在SELECT
中列出您想要GROUP BY
的所有字段。这很笨拙,所以你能做的最好的事情是upgrade to PostgreSQL 9.1 or 9.2, which are no longer subject to this limitation。
由于您正在使用查询生成器,处理此问题变得更加复杂。您不能只修改您的SQL。如果你无法升级PostgreSQL,你需要弄清楚如何说服你的查询生成器GROUP BY
表中的所有列。
如果savings.product_id
不是主键,则您的查询完全错误。您必须在SELECT
的{{1}}列表中列出所需的每个字段,以保证唯一且明确的结果,或仅引用聚合函数中的字段。
MySQL无论如何都会执行此查询,但它依赖于您知道结果将是明确的。如果某个字段有多个可能的值,它只会选择它首先获得的任何值。
在这种情况下,很难弄清楚你的查询实际应该做什么以及你期望得到什么结果。
答案 2 :(得分:1)
谢谢大家的帮助,我最终做到了这一点,并且正在本地开展PG工作!
Saving.select("DISTINCT ON (savings.product_id) * ").where{product_id.not_in(current_user_savings.select{product_id})}.group("savings.user_id, savings.updated_at, savings.id, savings.product_id, savings.price,savings.wishlist_id, savings.saved, savings.created_at")
有了这个问题让我将我的数据库从mysql切换到dev中的pg所以在heroku中没有更多的惊喜!
答案 3 :(得分:0)
您的SQL在PG中不起作用,MySQL将允许您这样做但不允许其他任何DBMS
此查询:
SELECT "savings".* FROM "savings"
WHERE "savings"."product_id"
NOT IN (SELECT "savings"."product_id" FROM "savings"
WHERE "savings"."user_id" = 1)
GROUP BY "savings"."product_id"
应该是
SELECT "savings"."product_id", count(*) FROM "savings"
--change this to your AGGR func
WHERE "savings"."product_id"
NOT IN (SELECT "savings"."product_id" FROM "savings"
WHERE "savings"."user_id" = 1)
GROUP BY "savings"."product_id"