I have this query that seems to work in pgAdmin. But when I try to translate it to are using scuttle I get a massive query fragment containing whole case statement. How do I refactor this query so that I can use it in Arel?
SELECT products.*, case when
(select custom_fields.value_text
from custom_fields
where custom_fields.custom_field_definition_id = 4
and custom_fields.table_record_id = products.id and custom_fields.belongs_to_table = 'product') is null
then 'stopped'
when
(select custom_fields.value_text
from custom_fields
where custom_fields.custom_field_definition_id = 4
and custom_fields.table_record_id = products.id and custom_fields.belongs_to_table = 'product') is not null
then (select custom_fields.value_text from custom_fields where custom_fields.custom_field_definition_id = 4
and custom_fields.table_record_id = products.id and custom_fields.belongs_to_table = 'product')
end as sorted
from products
order by sorted
Additional information: I have created a sqlite database that shows expected behaviour and could be used for further experiments.
https://github.com/bigos/rails-sorting/blob/master/README.org
Initial conclusion: I found a way to get expected results, but can no longer use it with Active Record methods. Luckily, I found how to paginate an array of hashes.
Best solution: I can return proper Active record relations if I put my code as a subquery in order by.
SELECT products.*
FROM products
ORDER BY (case when
(select custom_fields.value_text
from custom_fields
where custom_fields.custom_field_definition_id = 4
and custom_fields.table_record_id = products.id and custom_fields.belongs_to_table = 'product') is null
then 'stopped'
when
(select custom_fields.value_text
from custom_fields
where custom_fields.custom_field_definition_id = 4
and custom_fields.table_record_id = products.id and custom_fields.belongs_to_table = 'product') is not null
then (select custom_fields.value_text from custom_fields where custom_fields.custom_field_definition_id = 4
and custom_fields.table_record_id = products.id and custom_fields.belongs_to_table = 'product')
end )
I don't know exactly what problem you're facing getting this to work from your other tools and/or Active Record but the queries below ought to be equivalent and probably faster:
select p.*, coalesce(cf.value_text, stopped) as sorted
from
products p
left outer join custom_fields cf
on cf.table_record_id = p.id
and cf.belongs_to_table = 'product'
and cf.custom_field_definition_id = 4
order by sorted
This type of query is one of the reason that these kinds of "custom fields" tables are best avoided if possible.
Another alternative which is very close to your original approach is to use a scalar subquery inside a coalesce
. You might even prefer this way since it will cause an error if there's some way for the subquery to return more than one value.
select
p.*,
coalesce(
(
select custom_fields.value_text
from custom_fields cf
where
f.table_record_id = p.id
and cf.custom_fields.belongs_to_table = 'product'
and cf.custom_field_definition_id = 4
),
'stopped'
) as sorted
from products p
order by sorted