如何在rails中查询查询结果(使用rails查询'DISTINCT ON'的结果&postgres
简版: 我想查询另一个查询的结果,以便选择一个更有限的结果集但是,添加where子句重写第一个查询,而不是对结果的工作,所以我没有得到我想要的答案如何在rails中查询查询结果(使用rails查询'DISTINCT ON'的结果&postgres
的细节:。 我有两个型号,检查和ticks.Checks has_many ticks
第一个查询使用DISTINCT ON并收集所有'检查'和所有r兴高采烈的滴答,但只返回最近的滴答。我在模型中作为范围工作。
在我的控制器,
def checklist
#Filter the results by scope or return all checks with latest tick
case params[:filter]
when "duebylastresult"
@checks = Check.mostrecenttickonly.duebylastresult
when "duebydate"
@checks = Check.mostrecenttickonly.duebydate
else
@checks = Check.mostrecenttickonly
end
end
在该模型中,第一个范围(工作):
scope :mostrecenttickonly, -> {
includes(:ticks)
.order("checks.id, ticks.created_at DESC")
.select("DISTINCT ON (checks.id) *").references(:ticks)
}
生成以下SQL:
Parameters: {"filter"=>""}
SQL (1.0ms) SELECT DISTINCT ON (checks.id) *,
"checks"."id" AS t0_r0,
"checks"."area" AS t0_r1, "checks"."frequency" AS t0_r2,
"checks"."showinadvance" AS t0_r3, "checks"."category" AS t0_r4,
"checks"."title" AS t0_r5, "checks"."description" AS t0_r6,
"checks"."created_at" AS t0_r7, "checks"."updated_at" AS t0_r8,
"ticks"."id" AS t1_r0, "ticks"."result" AS t1_r1,
"ticks"."comments" AS t1_r2, "ticks"."created_at" AS t1_r3,
"ticks"."updated_at" AS t1_r4, "ticks"."check_id" AS t1_r5
FROM "checks" LEFT OUTER JOIN "ticks"
ON "ticks"."check_id" = "checks"."id"
ORDER BY checks.id, ticks.created_at DESC
已经得到了结果,我只想显示具有等于或大于3的值的刻度,所以范围:
scope :duebylastresult, -> { where("ticks.result >= 3") }
生成SQL
Parameters: {"filter"=>"duebylastresult"}
SQL (1.0ms) SELECT DISTINCT ON (checks.id) *,
"checks"."id" AS t0_r0,
"checks"."area" AS t0_r1, "checks"."frequency" AS t0_r2,
"checks"."showinadvance" AS t0_r3, "checks"."category" AS t0_r4,
"checks"."title" AS t0_r5, "checks"."description" AS t0_r6,
"checks"."created_at" AS t0_r7, "checks"."updated_at" AS t0_r8,
"ticks"."id" AS t1_r0, "ticks"."result" AS t1_r1,
"ticks"."comments" AS t1_r2, "ticks"."created_at" AS t1_r3,
"ticks"."updated_at" AS t1_r4, "ticks"."check_id" AS t1_r5
FROM "checks" LEFT OUTER JOIN "ticks"
ON "ticks"."check_id" = "checks"."id"
WHERE (ticks.result >= 3)
ORDER BY checks.id, ticks.created_at DESC
尽我所知道的,WHERE语句在行动前的DISTINCT ON子句,所以我现在有“其结果为> = 3最新滴答”,而我正在寻找'最近的滴答,那么只有当结果是> = 3'时。
希望有道理&在此先感谢!
编辑 - 是我所得到什么,我需要的例子:
The Data:
Table Checks:
ID: 98 Title: Eire
ID: 99 Title: Land
Table Ticks:
ID: 1 CheckID: 98 Result:1 Date: Jan12
ID: 2 CheckID: 98 Result:5 Date: Feb12
ID: 3 CheckID: 98 Result:1 Date: Mar12
ID: 4 CheckID: 99 Result:4 Date: Apr12
First query returns the most recent result, like;
Check.ID: 98 Tick.ID: 3 Tick.Result: 1 Tick.Date: Mar12
Check.ID: 99 Tick.ID: 4 Tick.Result: 4 Tick.Date: Apr12
Second query currently returns the most recent result where the result is =>3, like;
Check.ID: 98 Tick.ID: 2 Tick.Result: 5 Tick.Date: Feb12
Check.ID: 99 Tick.ID: 4 Tick.Result: 5 Tick.Date: Apr12
When I really want:
Check.ID: 99 Tick.ID: 4 Tick.Result: 5 Tick.Date: Apr12
(ID 98 doesn't show as the last Tick.Result is 1).
你能尝试以下,看看它是否开始你在正确的方向:
scope :just_a_test, -> {
includes(:ticks)
.order("checks.id")
.where("ticks.created_at = (SELECT MAX(ticks.created_at) FROM ticks WHERE ticks.check_id = checks.id)")
.where("ticks.result >= 3")
.group("checks.id")
}
那么,我试过你编辑前的版本, 范围:mostrecenttickonly, - > { 包括(:ticks) .order(“checks.id”) 。where(“ticks.created_at =(SELECT MAX(ticks。 created_at)FROM ticks WHERE ticks.check_id = checks.id)“) } 它给出了一个错误,因此添加了”.references(:ticks)“....它看起来像所有的工作! 我会在早上和你的新建议一起进一步测试,但很可能我会将此标记为答案 - 许多人非常感谢! –
目前的版本是否能给你想要的最终结果?如果是这样,我认为你可以删除第二个where子句并将其用于'''mostrecenttickonly''' – laertiades
谢谢@laertiades,回答接受。我还编辑了你的答案,以添加与.references一起工作的代码(目前正在等待同行评审)。再次感谢! –
我米不知道我真的明白:mostrecenttickonly
范围的点,因为你只是加载检查。
话虽这么说,如果你想获得只有那些检查其最近的蜱有大于三的结果,我认为要做到这一点的最佳方式将是一个window function:
check.rb
...
scope :duebylastresult, -> {
find_by_sql(
'SELECT *
FROM (SELECT checks.*,
ticks.id AS tick_ids,
ticks.date AS tick_date,
ticks.result AS tick_result,
dense_rank() OVER (
PARTITION BY checks.id
ORDER BY ticks.date DESC
) AS tick_rank
FROM checks
LEFT OUTER JOIN ticks ON checks.id = ticks.check_id) AS ranked_ticks
WHERE tick_rank = 1 AND tick_result >= 3;'
)
}
...
基本上,我们只是在检查连接一切,蜱表,然后添加名为tick_rank
是在结果根据其date
相对于相同其他行集居各行的另一个属性值。
的方式SQL工作原理是,谓词(在WHERE
子句中的条件)的SELECT
领域的评估之前评估的,这意味着我们不能只写tick_rank = 1
本声明。
所以我们必须去包装结果(我们别名为ranked_ticks
)的额外步骤,然后选择所有内容并将我们想要的谓词应用于此外部选择语句。该tick_rank
必须是1
,这意味着它最近tick
,其结果必须是> = 3
编辑:我用的是那篇文章我联系的复习,因为我常常忘记SQL语法,但看着它之后,我认为这将在一定程度上更好的性能(基本上只是迫不及待地加入checks
直到划分完成后,这样,我相信它会做较少的完全扫描):
scope :duebylastresult, -> {
find_by_sql(
'SELECT *
FROM checks
LEFT OUTER JOIN
(SELECT id AS tick_id,
check_id AS check_id,
date AS tick_date,
result AS tick_result,
dense_rank() OVER (
PARTITION BY ticks.check_id
ORDER BY ticks.date DESC
) AS tick_rank
FROM ticks) AS ranked_ticks ON checks.id = ranked_ticks.check_id
WHERE tick_rank = 1 AND tick_result >= 3;'
)
}
感谢@RobWise的附加解释,他们帮助我提高了我对sql的理解。具有以下特征的原因:最具挑战性的范围是,这是显示所有内容的视图,然后用户可以选择不同的视图。通过分两步来理解每个视图对我来说更容易。 –
你能举例说明现有查询的结果将如何变化不是比所需的查询? –
谢谢@RobWise,添加了示例。 –