假设我的Parent
模型有很多Child
,Child
也属于OtherParent
。
如何找到所有Parent
所有Child
属于OtherParent
的所有Parent.find_by_sql(<<SQL)
SELECT *
FROM parents p
WHERE NOT EXISTS (
SELECT *
FROM children
WHERE parent_id = p.id
AND other_parent_id IS NULL
)
SQL
?
在纯SQL中,我可以做到
function create_dwb_menu() {
global $wp_admin_bar;
$menu_id = 'dwb';
$wp_admin_bar->add_menu(array('id' => $menu_id, 'title' => __('DWB'), 'href' => '/'));
$wp_admin_bar->add_menu(array('parent' => $menu_id, 'title' => __('Homepage'), 'id' => 'dwb-home', 'href' => '/', 'meta' => array('target' => '_blank')));
$wp_admin_bar->add_menu(array('parent' => $menu_id, 'title' => __('Drafts'), 'id' => 'dwb-drafts', 'href' => 'edit.php?post_status=draft&post_type=post'));
$wp_admin_bar->add_menu(array('parent' => $menu_id, 'title' => __('Pending Comments'), 'id' => 'dwb-pending', 'href' => 'edit-comments.php?comment_status=moderated'));
}
add_action('admin_bar_menu', 'create_dwb_menu', 2000);
(来自here),但如果可能的话,我更愿意利用ActiveRecord。
谢谢!
我使用的是Rails 4.2.1和PostgreSQL 9.3
答案 0 :(得分:3)
使用arel
可以让你走得更远。棘手的部分是如何使用arel
自己的查询语法编写整个查询?
以下是一个技巧:使用where
构建查询时,如果使用arel
条件,则可以免费获得一些额外的方法。例如,您可以使用.exists.not
来拖动您在那里的子查询,这将为您提供一个(NOT ( EXISTS (subquery)))
折腾到父项的where
- 子句中并且您已设置。
问题是,您如何参考所涉及的表格?你需要Arel。您可以使用Arel的where
及其丑陋的条件,例如a.eq b
。但为什么?由于它是一个相等的条件,你可以使用Rails的条件!您可以使用散列键引用要查询的表,但对于另一个表(在外部查询中),您可以使用其arel_table
。看这个:
parents = Parent.arel_table
Parent.where(
Child.where(other_parent_id: nil, parent_id: parents[:id]).exists.not
)
您甚至可以通过稍微使用字符串来减少Arel的使用,并依赖于您可以将子查询作为参数提供给Rails'where
。它没有多大用处,但它并没有强迫你过多地挖掘Arel的方法,所以你可以使用那个技巧或其他带有子查询的SQL运算符(还有其他的吗?):
parents = Parent.arel_table
Parent.where('NOT EXISTS (?)',
Child.where(parent_id: parents[:id], other_parent_id: nil)
)
这里的两个要点是:
where
方法的参数。答案 1 :(得分:2)
使用例外scuttle,您可以将任意SQL转换为ruby(ActiveRecord和ARel查询)
通过该工具,您的查询将转换为
Parent.select(Arel.star).where(
Child.select(Arel.star).where(
Child.arel_table[:parent_id].eq(Parent.arel_table[:id]).and(Child.arel_table[:other_parent_id].eq(nil))
).ast
)
拆分查询 -
Parent.select(Arel.star)
将查询Parent表中的所有列。Child.arel_table
带您进入Arel-world,让您在从ruby生成查询时获得更多功能。具体来说,Child.arel_table[:parent_id]
为您提供了一个Arel :: Attributes :: Attribute的句柄,您可以在构建查询时继续使用它。.eq
和.and
方法完全符合您的预期,让您构建任意深度和复杂度的查询。不一定“更干净”,但完全在红宝石中,这很不错。
答案 2 :(得分:-1)
给定Parent
和Child
,并且子项与belongs_to
处于OtherParent
关系(假定为Rails默认值):
Parent.joins(:childs).where('other_parent_id = ?', other_parent_id)