Heroku在我的Postgres-Query上输出错误说明:
的ActiveRecord :: StatementInvalid (PGError:错误:语法错误在或 “date”附近2011-05-03T13:58:22 + 00:00 app [web.1]:LINE 1:... 2011-05-31') GROUP BY EXTRACT(来自TIMESTAMP的年份 日期)|| ... EXT
开发中的SQLite查询按预期工作。这是代码:
def self.calculate(year, month, user_id, partner_id)
case ActiveRecord::Base.connection.adapter_name
when 'SQLite'
where(':user_id = entries.user_id OR :partner_id = entries.user_id', {
:user_id => user_id,
:partner_id => partner_id
}).
where('entries.date <= :last_day', {
:last_day => Date.new(year, month, 1).at_end_of_month
}).
select('entries.date, ' +
'sum(case when joint = "f" then amount_calc else 0 end) as sum_private, ' +
'sum(case when joint = "t" and user_id = ' + user_id.to_s + ' then amount_calc else 0 end) as sum_user_joint, ' +
'sum(case when joint = "t" and user_id = ' + partner_id.to_s + ' then amount_calc else 0 end) as sum_partner_joint, ' +
'sum(case when compensation = "t" and user_id = ' + user_id.to_s + ' then amount_calc else 0 end) as sum_user_compensation, ' +
'sum(case when compensation = "t" and user_id = ' + partner_id.to_s + ' then amount_calc else 0 end) as sum_partner_compensation '
).
group("strftime('%Y-%m', date)")
when 'PostgreSQL'
where(':user_id = entries.user_id OR :partner_id = entries.user_id', {
:user_id => user_id,
:partner_id => partner_id
}).
where('entries.date <= :last_day', {
:last_day => Date.new(year, month, 1).at_end_of_month
}).
select('entries.date, ' +
'sum(case when joint = "f" then amount_calc else 0 end) as sum_private, ' +
'sum(case when joint = "t" and user_id = ' + user_id.to_s + ' then amount_calc else 0 end) as sum_user_joint, ' +
'sum(case when joint = "t" and user_id = ' + partner_id.to_s + ' then amount_calc else 0 end) as sum_partner_joint, ' +
'sum(case when compensation = "t" and user_id = ' + user_id.to_s + ' then amount_calc else 0 end) as sum_user_compensation, ' +
'sum(case when compensation = "t" and user_id = ' + partner_id.to_s + ' then amount_calc else 0 end) as sum_partner_compensation '
).
group("EXTRACT(YEAR FROM TIMESTAMP date)||EXTRACT(MONTH FROM TIMESTAMP date)")
else
raise 'Query not implemented for this DB adapter'
end
end
我真的很感激任何提示。由于我已经在这里提出一个问题,我不确定两个查询中总和中的case when joint = "t"
,还有更好的方法吗?
更新
感谢peufeu和没有名字的马,代码现在看起来像:
when 'PostgreSQL'
where(':user_id = entries.user_id OR :partner_id = entries.user_id', {
:user_id => user_id,
:partner_id => partner_id
}).
where('entries.date <= :last_day', {
:last_day => Date.new(year, month, 1).at_end_of_month
}).
select('min(entries.date) as date, ' +
'sum(case when joint = false then amount_calc else 0 end) as sum_private, ' +
'sum(case when joint = true and user_id = ' + user_id.to_s + ' then amount_calc else 0 end) as sum_user_joint, ' +
'sum(case when joint = true and user_id = ' + partner_id.to_s + ' then amount_calc else 0 end) as sum_partner_joint, ' +
'sum(case when compensation = true and user_id = ' + user_id.to_s + ' then amount_calc else 0 end) as sum_user_compensation, ' +
'sum(case when compensation = true and user_id = ' + partner_id.to_s + ' then amount_calc else 0 end) as sum_partner_compensation '
).
group('EXTRACT(YEAR FROM "date"), EXTRACT(MONTH FROM "date")')
......并且工作得像预期的那样。
我的另一个陈述现在遇到了麻烦,我在这里编辑它,因为它似乎与peufeu的答案有关。型号/控制器:
def self.all_entries_month(year, month, user_id, partner_id)
mydate = Date.new(year, month, 1)
where(':user_id = entries.user_id OR (:partner_id = entries.user_id AND entries.joint = :true)', {
:user_id => user_id,
:partner_id => partner_id,
:true => true
}).
where(':first_day <= entries.date AND entries.date <= :last_day', {
:first_day => mydate,
:last_day => mydate.at_end_of_month
})
end
# group by tag and build sum of groups named group_sum
def self.group_by_tag
group('tag').
select('entries.*, sum(amount_calc) as group_sum')
end
控制器:
@income = Entry.all_entries_month(@year, @month, current_user.id, current_partner.id).income
@cost = Entry.all_entries_month(@year, @month, current_user.id, current_partner.id).cost
# group cost by categories
@group_income = @income.group_by_tag.order('group_sum desc')
@group_cost = @cost.group_by_tag.order('group_sum')
错误是:
ActionView::Template::Error (PGError: ERROR: column "entries.id" must appear in the GROUP BY clause or be used in an aggregate function
2011-05-03T18:35:20+00:00 app[web.1]: : SELECT entries.*, sum(amount_calc) as group_sum FROM "entries" WHERE (1 = entries.user_id OR (2 = entries.user_id AND entries.joint = 't')) AND ('2011-04-01' <= entries.date AND entries.date <= '2011-04-30') AND (amount_calc <= 0 AND compensation = 'f') GROUP BY tag ORDER BY group_sum):
2011-05-03T18:35:20+00:00 app[web.1]: 6: </thead>
2011-05-03T18:35:20+00:00 app[web.1]: 7: <tbody>
2011-05-03T18:35:20+00:00 app[web.1]: 8: <% if categories %>
2011-05-03T18:35:20+00:00 app[web.1]: 9: <% categories.each do |category| %>
2011-05-03T18:35:20+00:00 app[web.1]: 10: <tr>
2011-05-03T18:35:20+00:00 app[web.1]: 11: <td class="align-left"><%= category.tag %></td>
2011-05-03T18:35:20+00:00 app[web.1]: 12: <td class="align-right"><%= my_number_to_percentage (category.group_sum.to_f / total_cost) * 100 %></td>
更新2:我找到了解决方案
# group by tag and build sum of groups named group_sum
def self.group_by_tag
group('tag').
select('tag, sum(amount_calc) as group_sum')
end
答案 0 :(得分:3)
问题在于:
EXTRACT(YEAR FROM TIMESTAMP date)||EXTRACT(MONTH FROM TIMESTAMP date)
解决方案:
EXTRACT(YEAR FROM "date"), EXTRACT(MONTH FROM "date")
“TIMESTAMP”这个词有点不合适;)......还有:
由于DATE是一个保留的SQL关键字,因此将它用作列名是一个非常糟糕的主意。在这里,我引用它“所以postgres不会混淆。
并且您不需要浪费CPU时间来构建连接两个EXTRACT的字符串,只需记住GROUP BY可以使用多个参数。
然后当然查询将失败,因为你选择“日期”,但你不要'GROUP BY日期。 postgres无法从具有相同Year-Month的所有行知道您想要的日期。 MySQL将从行中随机返回一个值,postgres喜欢正确性,因此会抛出错误。例如,你可以选择min(date),这是正确的。
我不确定关于=“t”
的情况
这取决于你想要的结果,没有错。
使用多个查询可能会扫描表格的一小部分(我不知道您的数据集)或者可能没有。
答案 1 :(得分:1)
我不知道ruby / heroku,但是表达
joint = "t"
指的是PostgreSQL中的列 t
,因为对象名称引用了双引号。因此,除非Ruby / Heroku用单引号替换那些双引号,否则这将是无效条件。
如果t
应该是字符串文字(字符t),那么您需要使用单引号:joint = 't'
如果joint
的类型为boolean
,那么您应该在PostgreSQL中使用joint = true