Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to join on subqueries using ARel?

I have a few massive SQL request involving join across various models in my rails application. A single request can involve 6 to 10 tables.

To run the request faster I want to use sub-queries in the joins (that way I can filter these tables before the join and reduce the columns to the ones I need). I'm trying to achieve this using ARel.

I thought I found the solution to my problem there: How to do joins on subqueries in AREL within Rails, but things must have changed because I get undefined method '[]' for Arel::SelectManager.

Does anybody have any idea how to achieve this (without using strings) ?

like image 437
Pierre Schambacher Avatar asked Apr 03 '13 13:04

Pierre Schambacher


People also ask

How do you join a subquery in SQL?

JOIN a table with a subquery A subquery can be used with JOIN operation. In the example below, the subquery actually returns a temporary table which is handled by database server in memory. The temporary table from the subquery is given an alias so that we can refer to it in the outer select statement.

What is the syntax of the subquery with the all operator?

The syntax of the subquery when it is used with the ALL operator is as follows: comparison_operator ALL (subquery) The following condition evaluates to true if x is greater than every value returned by the subquery. x > ALL (subquery) For example, suppose the subquery returns three value one, two, and three.

How to use a subquery in the FROM clause of the select?

You can use a subquery in the FROM clause of the SELECT statement as follows: SELECT * FROM (subquery) AS table_name Code language: SQL (Structured Query Language) (sql) In this syntax, the table alias is mandatory because all tables in the FROM clause must have a name.

What is Arel table in SQL?

The Arel::Table object acts like a hash which contains each column on the table. The columns given by Arel are a type of Node, which means it has several methods available on it to construct queries.


2 Answers

Pierre, I thought a better solution could be the following (inspiration from this gist):

a = A.arel_table  
b = B.arel_table

subquery = b.project(b[:a_id].as('A_id')).where{c > 4}  
subquery = subquery.as('intm_table')  
query = A.join(subquery).on(subquery[:A_id].eq(a[:id]))

No particular reason for naming the alias as "intm_table", I just thought it would be less confusing.

like image 50
Ashwin Saval Avatar answered Sep 25 '22 12:09

Ashwin Saval


OK so my main problem was that you can't join a Arel::SelectManager ... BUT you can join a table aliasing. So to generate the request in my comment above:

a = A.arel_table
b = B.arel_table

subquery = B.select(:a_id).where{c > 4}
query = A.join(subquery.as('B')).on(b[:a_id].eq(a[:id])
query.to_sql # SELECT A.* INNER JOIN (SELECT B.a_id FROM B WHERE B.c > 4) B ON A.id = B.a_id 
like image 32
Pierre Schambacher Avatar answered Sep 21 '22 12:09

Pierre Schambacher