我注意到StackOverflow上有一些类似的问题,但到目前为止我没有任何工作。我会尽量保持这个尽可能短。
我正在构建一个需要返回许多可能有或没有合同的问题的查询,这些问题可能会也可能不会完成(completed_at将被设置为DateTime,而不是nil)。每行需要包括:
all
记录字段issue
行
description
budget_item
completed_at
的{{1}}日期(一个contract
可能有0 budget_item
,1 contracts
},或5 + contract
,其中任意数量可以打开(completed_at:nil)或关闭(completed_at:DateTime)这是我到目前为止(返回正确的行数,但它返回最近创建的合同,而不是最新的合同
contracts
模型中的代码如下:
BaseItem.issues
.joins('LEFT JOIN budget_items
ON issues.id = budget_items.issue_id
LEFT JOIN contracts
ON budget_items.id = contracts.budget_item_id')
.select('issues.*, budget_items.description, contracts.completed_at AS resolved_at')
.group('issues.id')
.order('contracts.completed_at')
最终结果必须是:
可能会有多个class BaseItem < ActiveRecord::Base
has_many :issues
...
end
class Issue < ActiveRecord::Base
belongs_to :base_item
has_many :budget_items
...
end
class BudgetItem < ActiveRecord::Base
belongs_to :issue
has_many :contracts
...
end
class Contract < ActiveRecord::Base
belongs_to :budget_item
...
end
组成不同的行。每个issues
至少有四个issue
,仅用于需要出现在最终查询中的budget_items
,然后用于将每个budget_item.description
加入其中issue
contracts
{1}} {每个budget_item
可以有2个或3个contracts
,因此issue
最终可能会有8到12 contracts
。contracts
来自completed_at
查询需要根据其AS resolved_at
属性对其进行排序,并仅返回contract
最近completed_at
个completed_at: nil
日期。如果有4个合同,则有{{1} }},查询应该返回剩余的两个completed_at
日期中最近的一个作为该特定resolved_at
的{{1}}字段。
任何帮助都会非常赞赏,如果我需要提供任何其他信息,请与我们联系。
-Dave
结果查询(来自评论):
issue
答案 0 :(得分:1)
.order('contracts.completed_at DESC LIMIT 1')
(或者我不明白你的代码中缺少什么?)
答案 1 :(得分:1)
您不需要在示例中显示实际数据,以使其有用......
这就是我的意思。您可以在下面的示例数据中提出您的问题:
<强>问题强>
id base_item_id
-- ------------
10 6
20 6
30 6
99 123
<强> budget_items 强>
id issue_id description
-- -------- -----------
1 10 'one contract, none completed'
2 20 'one contract, one completed'
3 30 'two contracts, one completed'
4 30 'three contracts, two completed'
<强>合同强>
id budget_item_id completed_at
-- -------------- ------------
1 1 NULL
2 2 2015-01-02
3 3 2015-01-03
4 3 NULL
5 4 2015-01-05
6 4 NULL
7 4 2015-01-07
预期结果
issues.id contracts.completed_at budget_item.description
--------- ---------------------- -----------------------
10 NULL NULL
20 2015-01-02 one contract, one completed
30 2015-01-07 three contracts, two completed
这是你想要的吗?我的样本数据是否涵盖所有可能的边缘情况?如果没有,请向其添加更多行,并显示它对结果的影响。
这是最终查询的样子。 MySQL不具备CROSS APPLY
或LATERAL JOINS
之类的东西,因此效率低于其他数据库 - 子查询将运行两次。
我不知道如何将这个SQL翻译成Ruby - 我从未使用过Ruby。
SELECT
issues.*
,(
SELECT contracts.completed_at
FROM
budget_items
INNER JOIN contracts ON contracts.budget_item_id = budget_items.id
WHERE
budget_items.issue_id = issues.id
AND contracts.completed_at IS NOT NULL
ORDER BY contracts.completed_at DESC
LIMIT 1
) AS resolved_at
,(
SELECT budget_items.description
FROM
budget_items
INNER JOIN contracts ON contracts.budget_item_id = budget_items.id
WHERE
budget_items.issue_id = issues.id
AND contracts.completed_at IS NOT NULL
ORDER BY contracts.completed_at DESC
LIMIT 1
) AS description
FROM issues
WHERE issues.base_item_id = 6
主要想法很简单。我们为每个issue
返回一行。对于每个问题,我们会找到一个最新的contract
,使用您需要的任何条件(例如contracts.completed_at IS NOT NULL
仅查找已完成的合同)。
如果contracts
根本没有完成issue
,则NULL
和description
会返回resolved_at
。您可以在主SELECT
中添加额外的过滤条件,以便在您想要的时候移除此类行(WHERE issues.base_item_id = 6 AND resolved_at IS NOT NULL
)。