Rails - Using SELECT in a WHERE clause - ruby-on-rails

I'm trying to make a Rails model scope based on the following query:
SELECT * FROM tableA a
INNER JOIN tableB b ON a.id = b.id
WHERE a.id = (SELECT MAX(id) FROM tableB WHERE field = a.field)
I want to join rows of tableA with only one of tableB rows (the max one).
Is it possible?
Thank you!

TableA
.joins(:tableB)
.where("a.id = (SELECT MAX(id) FROM tableB WHERE field = a.field)")
You'll need to have an association between the two tables if you want the joins method works

Related

Trying to fetch data from table with good performance

I am trying to fetch customer and owner data
customer
|cnumber |id |
|080204220 |32859471000|
|907501981|6029151000|
role
|id|type|
|32859471000|owner|
|6029151000|customer|
result set
id|number|owner number|type|
|32859471000|080204220 |080204220 | owner
|6029151000|907501981|080204220 |customer
query
select c.id,sub.cnumber,c.cnumber, r.roletype
from customer c
inner join role r on c.id = r.id
left outer join (select c.cnumber ,r.roletype,c.id
from customer c
INNER JOIN role r
ON c.id = r.id ) sub on sub.roletype='owner';
This query gives proper result, but left outer join with same tables may cause impact on performance, is there any other way to achieve this?
I would prefer you to go with this only.
select c.id,sub.cnumber,c.cnumber, r.roletype
from customer c
inner join role r on c.id = r.id
left outer join (select c.cnumber ,r.roletype,c.id
from customer c
INNER JOIN role r
ON c.id = r.id ) sub on sub.roletype='owner';
As far as I can get the logic, you need to display an "owner"-customer among all of the others.
Since there is only one owner in the example data, I'd do it using the "cross join" (cartesian join)
select c.id,sub.cnumber,c.cnumber, r.roletype
from customer c
inner join role r on c.id = r.id
cross join (select c.cnumber ,r.roletype,c.id
from customer c
INNER JOIN role r
ON c.id = r.id where r.roletype='owner') sub
select c.id,sub.cnumber,c.cnumber, r.roletype
from customer c
inner join role r on c.id = r.id
left outer join (select c.cnumber ,r.roletype,c.id
from customer c
INNER JOIN role r
ON c.id = r.id ) sub on sub.roletype='owner';

How to only join on numeric values

Right now I have:
select
a.id
b.colone
b.coltwo
from tablea a
left join tableb b on b.id = a.id
I'm getting the "numeric value not recognized" error because one value from b.id is not numeric. How do I join results from tableb to tablea just omitting the non-numeric value/row? Or how else can I bypass this error? Using snowflake.
Thank you!
You can use TRY_TO_NUMBER():
select
a.id
b.colone
b.coltwo
from tablea a
left join tableb b on TRY_TO_NUMBER(b.id) = a.id

How to join a table and then table inside table in mysqli?

I have a table name
deposite with columns deposite_id, assigncourse_id
and assigncourse table with columns assigncourse_id, std_id, course_id
and two tables std and course
now i want to join assigncourse table from deposite table and then join with std and course table from assigncourse table, with mysqli query.
SELECT *
FROM deposite d
JOIN (SELECT a.assigncourse_id
FROM assigncourse a
JOIN std t ON a.std_id = t.std_id
JOIN course c ON a.course_id = c.course_id
) m ON d.assigncourse_id = m.assigncourse_id;

RIGHT OUTER JOIN returns empty results with WHERE

I need to produce a report of all records (businesses) created by a particular user each month over last months. I produced the following query and expect it to provide me with a row for each month. However, this user didn't create any records (businesses) these months so I get an empty result [].
I'm still expecting to receive a row for each month, since I'm selecting a generate_series column using RIGHT OUTER JOIN but it doesn't happen.
start = 3.months.ago
stop = Time.now
new_businesses = Business.select(
"generate_series, count(id) as new").
joins("RIGHT OUTER JOIN ( SELECT
generate_series(#{start.month}, #{stop.month})) series
ON generate_series = date_part('month', created_at)
").
where(created_at: start.beginning_of_month .. stop.end_of_month).
where(author_id: creator.id).
group("generate_series").
order('generate_series ASC')
How can I change my query to get a row for each month instead of an empty result? I'm using PosgreSQL.
UPDATE
This code works:
new_businesses = Business.select(
"generate_series as month, count(id) as new").
joins("RIGHT OUTER JOIN ( SELECT
generate_series(#{start.month}, #{stop.month})) series
ON (generate_series = date_part('month', created_at)
AND author_id = #{creator.id}
AND created_at BETWEEN '#{start.beginning_of_month.to_formatted_s(:db)}' AND
'#{stop.end_of_month.to_formatted_s(:db)}'
)
").
group("generate_series").
order('generate_series ASC')
Your problem is in the where part which is breaks any outer joins. Consider the example:
select *
from a right outer join b on (a.id = b.id)
It will returns all rows from b and linked values from a, but:
select *
from a right outer join b on (a.id = b.id)
where a.some_field = 1
will drops all rows where a is not present.
The right way to do such sings is to place the filter into the join query part:
select *
from a right outer join b on (a.id = b.id and a.some_field = 1)
or use subquery:
select *
from (select * from a where a.some_field = 1) as a right outer join b on (a.id = b.id)

How to write the below SQL query in rails 3 ActiveRecord?

select * from
(
SELECT DISTINCT ON (table1.id) table1.*, table3.date_filed as date_filed
FROM
table1 LEFT JOIN table2 ON table2.id = table1.some_id
INNER JOIN table3 ON table2.id = table3.some_id
WHERE
(
status IN('Supervisor Accepted')
)
AND(table3.is_main)
)first_result
ORDER BY date_filed ASC LIMIT 25 OFFSET 0
Is there any way to run main/subset query in the database side through Active::record (Rails 3). I don't want run the first_result(First db query) and the order by on the top of the result(Second db query).
I tried the below:
# First query run
first_result = Table1.select('DISTINCT ON (table1.id) table1.*, table3.date_filed').
joins('LEFT JOIN table2 ON table2.id = table1.some_id'). # I don't want a association here
joins('INNER JOIN table3 ON table2.id = table3.some_id').
where('table3.is_main')
# Second query run, WHICH is UGLY and not working properly
Table1.where(id: first_result.collect(:&id)).
order_by('date_filed ASC')
page(page).
per_page(per_page)

Resources