MySQL Aggregate Query using CodeIgniter’s Query Builder

CodeIgniter’s Query Builder ORM has class methods for nearly any kind of database access/operation you can think of. In this post, I’ll cover some of the available methods for retrieving aggregate-level query results. The examples in this post map out Query Builder method chaining to produce results you would get from a raw MySQL query. Continue reading to see more…

Self-Promotion:

If you enjoy the content written here, by all means, share this blog and your favorite post(s) with others who may benefit from or like it as well. Since coffee is my favorite drink, you can even buy me one if you would like!


MySQL Query prototyping

When working on Back-end PHP code, I typically prototype out MySQL queries using either MySQL Workbench or phpMyAdmin. Once I have the correct query results, I then translate the MySQL query over to the PHP layer. For applications written in core PHP, I tend to use the PDO class.

However, when using CodeIgniter 4 (which is my PHP framework of choice at this time), you can use any of these options: 

For the examples in this post, I will use Query Builder class methods which are specific for aggregate-level data.

Aggregate Query Results using MySQL

As a SQL-first type of developer, I can honestly say that SQL is my favorite programming language and I am comfortable writing MySQL queries. That being said, I do appreciate the usefulness of an ORM.

In my particular instance, since I use the CodeIgniter framework, the combination of CodeIgniter’s Models and the Query Builder class makes querying quite easy, among other things.

Here is one such case in which I had little trouble retrieving the same query results using CodeIgniter Query Builder class ORM methods, as opposed to a raw MySQL query. I don’t feel that one approach is better or more valid than the other. This is just my experience as I learn CodeIgniter and am exposed to the Query Builder class and the in-built Models functionality provided by the framework.

Let’s review this MySQL query which retrieves aggregated data on some of the walking stats and metrics I am interested in:

SELECT
    MIN(`ws`.`day_walked`) AS `oldest_day_walked`, MAX(`ws`.`day_walked`) AS `recent_day_walk`,
    SUM(`ws`.`cal_burned`) AS `total_calories_burned`, SUM(`ws`.`miles_walked`) AS `total_miles_walked`,
    COUNT(*) AS `number_of_walks`, `sw`.`brand_name`
FROM `walking_stats` AS `ws`
INNER JOIN `shoes_worn` AS `sw`
ON `ws`.`shoe_id` = `sw`.`shoe_id`
GROUP BY `sw`.`brand_name`
ORDER BY `sw`.`brand_name` ASC;

Nothing too extravagant. A typical query using SUM(), COUNT(), MIN(), and MAX() aggregate functions. 

The above query returns these results:

mysql aggregate query results
MySQL aggregate query results.

Aggregate Query Results using CodeIginiter Query Builder class methods

But, is this type of query – and more importantly – the query results, easily reproduced using CodeIgniter 4’s Query Builder class methods? They absolutely are.

Let’s visit this CodeIgniter method I have in a class which extends the CodeIgniter Model:

CodeIgniter 4 Query Builder class aggregate methods
CodeIgniter 4 Query Builder class aggregate methods.

The 4 key Query Builder aggregate-type methods used in the above Model method are:

  1. selectMin() – Maps to: SELECT MIN(field_name)
  2. selectMax() – Maps to: SELECT MAX(field_name)
  3. selectSum() – Maps to: SELECT SUM(field_name)
  4. selectCount() – Maps to: SELECT COUNT(field_name)
Rounding out with both groupBy() and orderBy() methods complete the query.

(Note: All 4 of the methods accept an optional 2nd parameter used to rename the field. I think of this in the same context as aliasing a column in MySQL using the AS keyword.

The shoeAnalytics() model method produces identical query results as the MySQL query version shown previously. Looking at them in the browser using PHP”s print_r() method, we can see all of the data is there:

Array
(
    [0] => stdClass Object
        (
            [oldest_day_walked] => 2019-01-02
            [recent_day_walked] => 2020-12-02
            [total_calories_burned] => 9091.1
            [total_miles_walked] => 87.76
            [number_of_walks] => 35
            [brand_name] => Keen Koven WP
        )

    [1] => stdClass Object
        (
            [oldest_day_walked] => 2019-02-01
            [recent_day_walked] => 2020-12-20
            [total_calories_burned] => 1243.5
            [total_miles_walked] => 13.25
            [number_of_walks] => 5
            [brand_name] => Keen Targhee Vent
        )

    [2] => stdClass Object
        (
            [oldest_day_walked] => 2019-07-15
            [recent_day_walked] => 2020-05-13
            [total_calories_burned] => 36805.2
            [total_miles_walked] => 363.35
            [number_of_walks] => 114
            [brand_name] => Merrel MOAB Edge 2
        )

    [3] => stdClass Object
        (
            [oldest_day_walked] => 2019-02-15
            [recent_day_walked] => 2019-04-08
            [total_calories_burned] => 404.7
            [total_miles_walked] => 3.99
            [number_of_walks] => 2
            [brand_name] => New Balance Trail Runners-All Terrain
        )

    [4] => stdClass Object
        (
            [oldest_day_walked] => 2019-07-30
            [recent_day_walked] => 2021-02-17
            [total_calories_burned] => 21754.4
            [total_miles_walked] => 216.61
            [number_of_walks] => 75
            [brand_name] => Oboz Cirque Low
        )

    [5] => stdClass Object
        (
            [oldest_day_walked] => 2020-05-24
            [recent_day_walked] => 2020-12-04
            [total_calories_burned] => 31222.5
            [total_miles_walked] => 308.09
            [number_of_walks] => 105
            [brand_name] => Oboz Sawtooth II Low
        )

    [6] => stdClass Object
        (
            [oldest_day_walked] => 2019-01-01
            [recent_day_walked] => 2019-08-08
            [total_calories_burned] => 33084.5
            [total_miles_walked] => 327.59
            [number_of_walks] => 137
            [brand_name] => Oboz Sawtooth Low
        )

    [7] => stdClass Object
        (
            [oldest_day_walked] => 2020-10-05
            [recent_day_walked] => 2020-10-11
            [total_calories_burned] => 1172.3
            [total_miles_walked] => 11.42
            [number_of_walks] => 4
            [brand_name] => Skechers Crossbar
        )

)


Consider making a small donation on my behalf as I continue to provide useful and valuable content here on my site.

Thank you.


The shoeAnalytics() method can now provide these specific query results to any Views or libraries needing the data.

Other CodeIgniter Query Builder class methods

Which CodeIgniter Query Builder class methods do you find map nicely to a corresponding similar SQL expression? Which are those that do not map so nicely? Let me know in the comments!

Similar Reading

Visit any of the below PHP-related blog posts I have written if you are so inclined. Please share them with others who would benefit from the content as well.

Like what you have read? See anything incorrect? Please comment below and thank you for reading!!!

A Call To Action!

Thank you for taking the time to read this post. I truly hope you discovered something interesting and enlightening. Please share your findings here, with someone else you know who would get the same value out of it as well.

Visit the Portfolio-Projects page to see blog post/technical writing I have completed for clients.



To receive email notifications (Never Spam) from this blog (“Digital Owl’s Prose”) for the latest blog posts as they are published, please subscribe (of your own volition) by clicking the ‘Click To Subscribe!’ button in the sidebar on the homepage! (Feel free at any time to review the Digital Owl’s Prose Privacy Policy Page for any questions you may have about: email updates, opt-in, opt-out, contact forms, etc…)

Be sure and visit the “Best Of” page for a collection of my best blog posts.


Josh Otwell has a passion to study and grow as a SQL Developer and blogger. Other favorite activities find him with his nose buried in a good book, article, or the Linux command line. Among those, he shares a love of tabletop RPG games, reading fantasy novels, and spending time with his wife and two daughters.

Disclaimer: The examples presented in this post are hypothetical ideas of how to achieve similar types of results. They are not the utmost best solution(s). The majority, if not all, of the examples provided, are performed on a personal development/learning workstation-environment and should not be considered production quality or ready. Your particular goals and needs may vary. Use those practices that best benefit your needs and goals. Opinions are my own.

Have a look at all Apress PHP books and eBooks.

Hey thanks for commenting! Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.