我一直在尝试在我的Rails应用程序中转换mySQL查询以使用Postgres语法,并且一直在倾注Postgres文档,特别是查看条件之间的差异。查询是:
Story.select('*', 'IF (views.id is null, 0, 1) as viewed')
.join('left join views on(
views.story_id = stories.id and views.user_id = ?
)', user.id)
.group(:id)
.order(viewed: :asc)
.order(id: :asc)
或作为纯查询:
select stories.*,
IF (views.id is null, 0, 1) as viewed
from stories
left join views
on(views.story_id = stories.id and views.user_id = 1)
where 1
group by stories.id
order by viewed, stories.id
似乎postgres使用'case'而不是IF,所以我厌倦了这样的事情:
Story.select('*', '(case when viewid is null then 0, 1 end) as viewed')
.join('left join views on(
views.story_id = stories.id and view.user_id = ?
)', user.id)
.group(:id)
.order(viewed: :asc)
.order(id: :asc)
但是我得到了
错误的参数数量(2为0..1)
错误...
我尝试了几种变化,但没有运气。我打算在不久的将来更多地学习SQL,但同时我觉得有点迷失。
有人可以在这里指出不同语法的细节吗?谢谢!
答案 0 :(得分:1)
基于错误:
错误的参数数量(2为0..1)
Rails(没有postgres)告诉你某个方法正在接收两个参数,但该方法只支持或不支持参数或只支持一个参数。
查看代码,发送两个参数的唯一两种方法是select
和join
,所以如果你尝试的话:
select('*, (case when viewid is null then 0, 1 end) as viewed')
代替
select('*', '(case when viewid is null then 0, 1 end) as viewed')
和(仅用于测试,因为不良做法)
.join("left join views on(
views.story_id = stories.id and view.user_id = #{user.id}
)")
而不是
.join('left join views on(
views.story_id = stories.id and view.user_id = ?
)', user.id)
答案 1 :(得分:0)
EXISTS(...)
产生一个布尔值,它非常优雅地解决了NULL情况:
select s.*
, EXISTS (select 42 from views v
where v.story_id = s.id
and v.user_id = 1) as viewed
from stories s
where 1=1
;
如果要在viewed
子句中使用ORDER BY
列,则必须将上述查询推送到子查询中。
答案 2 :(得分:0)
使用带条件的单个查询最接近postgres语法转换:
select stories.*,
CASE WHEN views.id is null THEN 0 ELSE 1 END as viewed
from stories
left join views
on(views.story_id = stories.id and views.user_id = 1)
where true
group by stories.id, views.id
order by viewed, stories.id