Active Record is an extremely powerful abstraction on SQL, but many a Rails programmer tends to forget that that means the entirety of the SQL standard. While it might be common knowledge for some, aggregate queries seem to be missing from the toolkit of a newer rails programmer.
For this we’ll be using a model called Foo
with the fields a, b, and c. All of the fields are strings with random words chosen from OSX’s built in wordlist:
1 2 3 4 |
|
Count
How many times have you done this?
1
|
|
The problem with this one is quite simply that it’s retrieving all the records just to get a count. Seem inefficient? It is:
1 2 |
|
Instead, use the count method:
1 2 |
|
Let’s go ahead and blank out the a
field for the first thousand or so records. Note that I don’t use first, as that returns an array:
1 2 3 |
|
Now how would we get the count of records where a
is present? Count takes arguments:
1 2 3 |
|
Would you look at that, it’s over 9000!
Group
Let’s say we want to group our records by their length to find out how many words there are for a certain length. Ruby has a built in group_by
method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
That all
should be enough of a trigger to start looking for an aggregate method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
SQL functions are perfectly valid in this context, and quite helpful as well. Just using a column name in group, we can group by similar values as well.
Pluck
Pluck doesn’t just get certain columns from a database, it can also be used for SQL functions. Let’s say we want a list of what length of words we have:
1 2 3 |
|
How about the average length of our a
column?
1 2 3 |
|
Noted you can use the average(:a)
function here as well:
1 2 3 |
|
…but what you cannot do with average
, min
, max
, and other calculation functions is this useful tidbit:
1 2 3 |
|
That one, without aggregate functions, is likely to take quite a while indeed.
Calculations
There are some other common functions that may well come in handy if you only happen to need one value:
1 2 3 4 5 6 7 |
|
Where
Not an aggregate per-se, but using a where clause can still use SQL functions. Say you only want records with an a
field longer than 10 characters:
1 2 3 |
|
Maybe the count isn’t what you’re after. Perhaps you want the ids instead?:
1 2 3 4 5 6 |
|
Never underestimate the value of being familiar with basic functions in SQL, as they’ll save your database a lot of headaches.
Finishing up
While a strong knowledge of SQL is not always necessary for Rails development, it will most certainly improve your code and your performance. Not everything has to fit into hash arguments for a where clause.