I’m developing an online application for education research, where I frequently have the need for very complex SQL queries:
- queries usually include 5-20 joins, often joined to the same table several times
- the SELECT field often ends up being 30-40 lines tall, between derived fields / calculations and CASE statements
- extra WHERE conditions are added in the PHP, based on user’s permissions & other security settings
- the user interface has search & sort controls to add custom clauses to the WHERE / ORDER / HAVING clauses.
Currently this app is built on PHP + MYSQL + Jquery for the moving parts. (This grew out of old Dreamweaver code.) Soon we are going to rebuild the application from scratch, with the intent to consolidate, clean, and be ready for future expansion. While I’m comfortable in PHP, I’m learning bits about Rails and realizing, Maybe it would be better to build version 2.0 on a more modern framework instead. But before I can commit to hours of tutorials, I need to know if the Rails querying system (ActiveRecord?) will meet our query needs.
Here’s an example of one query challenge I’m concerned about. A query must select from 3+ “instances” of a table, and get comparable information from each instance:
SELECT p1.name AS my_name, pm.name AS mother_name, pf.name AS father_name
FROM people p1
JOIN mother pm ON p1.mother_id = pm.id
JOIN father pf ON p1.father_id = pf.id
# etc. etc. etc.
WHERE p1.age BETWEEN 10 AND 16
# (selects this info for 10-200 people)
Or, a similar example, more representative of our challenges. A “raw data” table joins multiple times to a “coding choices” table, each instance of which in turn has to look up the text associated with a key it stores:
SELECT d.*, c1.coder_name AS name_c1, c2.coder_name AS name_c2, c3.coder_name AS name_c3,
(c1.result + c2.result + c3.result) AS result_combined,
m_c1.selection AS selected_c1, m_c2.selection AS selected_c2. m_c3.selection AS selected_c3
FROM t_data d
LEFT JOIN t_codes c1 ON d.id = c1.data_id AND c1.category = 1
LEFT JOIN t_menu_choice m_c1 ON c1.menu_choice = m_c1.id
LEFT JOIN t_codes c2 ON d.id = c2.data_id AND c2.category = 2
LEFT JOIN t_menu_choice m_c2 ON c2.menu_choice = m_c2.id
LEFT JOIN t_codes c3 ON d.id = c3.data_id AND c3.category = 3
LEFT JOIN t_menu_choice m_c3 ON c3.menu_choice = m_c3.id
WHERE d.date_completed BETWEEN ? AND ?
AND c1.coder_id = ?
These sorts of joins are straightforward to write in pure SQL, and when search filters and other varying elements are needed, a couple PHP loops can help to cobble strings together into a complete query. But I haven’t seen any Rails / ActiveRecord examples that address this sort of structure. If I’ll need to run every query as pure SQL using find_by_sql(“”), then maybe using Rails won’t be much of an improvement over sticking with the PHP I know.
My question is: Does ActiveRecord support cases where tables need “nicknames”, such as in the queries above? Can the primary table have an alias too? (in my examples, “p1” or “d”) How much control do I have over what fields are selected in the SELECT statement? Can I create aliases for selected fields? Can I do calculations & select derived fields in the SELECT clause? How about CASE statements?
How about setting WHERE conditions that specify the joined table’s alias? Can my WHERE clause include things like (using the top example) ” WHERE pm.age BETWEEN p1.age AND 65 “?
This sort of complexity isn’t just an occasional bizarre query, it’s a constant and central feature of the application (as it’s currently structured). My concern is not just whether writing these queries is “possible” within Rails & ActiveRecord; it’s whether this sort of need is supported by “the Rails way”, because I’ll need to be writing a lot of these. So I’m trying to decide whether switching to Rails will cause more trouble than it’s worth.
Thanks in advance! – if you have similar experiences with big scary queries in Rails, I’d love to hear your story & how it worked out.
Short answer is Yes. Rails takes care of the large part of these requirements through various types of relations, scopes, etc. Most important thing is to properly model your application to support types of queries and functionality you are going to need. If something is difficult to explain to a person, generally will be very hard to do in rails. It’s optimized to handle most of “real world” type of relationships and tasks, so “exceptions” become somewhat difficult to fit into this convention, and later become harder to maintain, manage, develop further, decouple etc. Bottom line is that rails can handle sql query for you,
SomeObject.all_active_objects_with_some_quality, give you complete control over sqlSomeObject.find_by_sql("select * from ..."),execute("update blah set something=''...)and everything in between.One of advantages of rails allows you to quickly create prototypes, I would create your model concepts, and then test the most complex business requirements that you have. This will give you a quick idea of what is possible and easy to do vs bottlenecks and potential issues that you might face in development.