SQL 101: Aggregate Functions: Discovering SQL's Hidden Gems

SQL
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

SQL's ability to make sense of large sets of data by using simple functions that allow you to aggregate data is a major tool that every programmer should master. Learn how to make the most of SQL's aggregate functions.

 

How do you calculate a total amount based on detail records in RPG? You probably read each record, add the respective amount to a work variable, and move on to the next record, until the file (or subset of records) ends. Well, in SQL you can do the same with a single instruction. Let's explore the awesome power and flexibility of SQL's aggregate functions, making use of what I explained before about the Select SQL instruction. In that article, I introduced an Inventory Master Table, which I have been using in most examples. This table's name is InvMst, and its description is presented in the table below:

 

The InvMst File Description

Column Name

Data Type

Length

Column Description

ItemID

Character

15,0

Item ID

LotNbr

Decimal

13,0

Lot Number

ExpDate

Date

N/A

Expiration Date

WHID

Decimal

8,0

Warehouse ID

ShelfID

Decimal

12,0

Shelf ID

ItemUn

Character

3

Item Units

ItemQty

Decimal

9,2

Item Quantity

 

Let's see, for instance, how to return the total quantity of the Item with ID 'A123' that exists in warehouse 24. SQL provides several types of functions you can usetogether with constants, operators, and column namesto create all sorts of expressions. In this case, I'll use a SUM function, which does the same as its MS Excel counterpart: returns the sum of a set of values. Here's how you use it to get the total quantity of Item 'A123' that exists in warehouse 24:

 

SELECT      ItemID

            , SUM(ItemQty)

FROM        InvMst

WHERE       WHID = 24

GROUP BY    ItemID

 

Notice that last line, GROUP BY ItemID? This is a requirement of some functions, even though you can use it whenever you want to group results, regardless of the functions you specified in the Select clause. The Group By reserved expression does what its name implies (allows you to group the results by one or more columns), and its structure is similar to Order By (it also expects one or more column names). It will aggregate the records retrieved that have those columns' contents in common. In this simple example, I'm grouping by ItemID and getting a single line as a result, but I could add a comma and "ShelfID" to the Group By expression, and the aggregation would be different: I'd get a line per each ItemID / ShelfID combination.

 

In abstract terms, an aggregate function, such as the SUM, takes a set of values (like a column of data) and returns a single value result from the set of values. This set of values will be determined by the WHERE and GROUP BY clauses of your SQL statement.

 

One of the most commonly used is the average function. Calculating an average in RPG is not very difficult, but it requires a loop and at least two variables; you read your data in a loop, sum up the values into a variable, and increase a counter (your second variable). In the end, you just divide the sum by the counter and voilá! The average is calculated.

 

In SQL, however, there's a function for that: AVG. Its syntax is similar to SUM; you just need to specify the field name for which you want to calculate the average enclosed in parentheses after the function name: AVG(<field name>). You can use it in all DML statements, even though I can't imagine how this can be used in a Delete statement. Anyway, here's an example: calculating the average quantity of item 'A123' per shelf in warehouse 333 is as simple as this:

 

SELECT            ItemID

            , AVG(ItemQty)

FROM        InvMst

WHERE       ItemID = 'A123'

            AND WHID = 333

GROUP BY    ItemID, ShelfID

 

I'm grouping by ShelfID to guarantee that my average is per shelf. If I hadn't specified the GROUP BY clause, the average would be calculated for the warehouse 333. AVG has two optional and mutually exclusive keywords, ALL and DISTINCT, which you can use to include all values or disregard the duplicates, respectively. By default, all values are considered. In other words, specifying ALL is redundant. However, there may be times in which it makes sense to use DISTINCT. Here's the average calculation from the previous example, disregarding the duplicate item quantities:

 

SELECT            ItemID

            , AVG(DISTINCT ItemQty)

FROM        InvMst

WHERE       ItemID = 'A123'

            AND WHID = 333

GROUP BY    ItemID, ShelfID

 

When you run this statement, it will return a rather ugly AVG column value. Assuming that the average is one hundred, the returned value is 100.000000000000000000000000, because of the way the average is internally calculated by the database engine. You have a few different ways to "beautify" the output, similar to RPG's %EDITC and %EDITW, but let's take the opportunity to introduce another useful SQL instruction: CAST. SQL can work magic, but it doesn't cast spells; it casts data types. CAST's syntax is simple:

 

CAST ( <expression> as <data type>).

 

The following example transforms the average column into a DECIMAL (9, 2) column:

 

SELECT            ItemID

, CAST(AVG(DISTINCT ItemQty) AS dec (9,2))

FROM        InvMst

WHERE       ItemID = 'A123'

AND WHID = 24

GROUP BY   ItemId, ShelfId

 

I'm highlighting the changes in bold. You can use CAST in all the places you'd use a column or expression. However, you need to use it carefully, because some CAST operations require some processing, which will cause the operation to take longer.

 

If I wanted to count the shelves that contain the 'A123' item instead of calculating their average quantity, SQL also provides a simple to use function for that: COUNT. The syntax is similar to AVG in every way, right down to the ALL and DISTINCT keywords. The difference is, other than the obvious operation that is executed, you can use COUNT for any type of expression, while AVG only works with numeric expressions or fields. Here's a simple count scenario: I want to count how many shelves in warehouse 333 contain item 'A123':

 

SELECT            ItemID

            , COUNT(ShelfID)

FROM        InvMst

WHERE       ItemID = 'A123'

            AND WHID = 333

GROUP BY    ItemID

 

Here, the DISTINCT keyword is more relevant, because in a COUNT it might make sense to eliminate the duplicates. COUNT is commonly used to return the number of rows in a table; again using the InvMst table as an example, I'd use the following to calculate how many records InvMst has:

 

SELECT            COUNT(*)

FROM        InvMst

 

Note that COUNT returns a DECIMAL(15, 0) field; you need to use COUNT_BIG when the expected result is greater than the maximum value of an integer. COUNT_BIG works exactly like COUNT, with the difference that it can return a DECIMAL(31, 0) value as maximum output.

 

Some other times, you just need the maximum or minimum of a set of values. You can use MAX and MIN, respectively, to get those results. These two functions are similar to COUNT in every way, but using the DISTINCT keyword has no practical effect. If I wanted to return the minimum and maximum expiration dates of item 'A123' in warehouse 333, regardless of the shelf it sits in, I'd use the following statement:

 

SELECT            MIN(ItemQty)

            , MAX(ItemQty)

FROM        InvMst

WHERE       WHID = 333

 

As you can see from this example, you can use multiple column functions in the same statement. However, due to their specific nature, some are not compatible with each other and can't be used together.

 

Now that you're getting the hang of it, the next articles will discuss the scalar functions. Don't know what they are? Well, here's a sneak peek of what's coming: a scalar function takes input arguments and returns a single value result. The restrictions on the use of aggregate functions do not apply to scalar functions, because a scalar function is applied to single parameter values rather than to sets of values.

Rafael Victoria-Pereira

Rafael Victória-Pereira has more than 20 years of IBM i experience as a programmer, analyst, and manager. Over that period, he has been an active voice in the IBM i community, encouraging and helping programmers transition to ILE and free-format RPG. Rafael has written more than 100 technical articles about topics ranging from interfaces (the topic for his first book, Flexible Input, Dazzling Output with IBM i) to modern RPG and SQL in his popular RPG Academy and SQL 101 series on mcpressonline.com and in his books Evolve Your RPG Coding and SQL for IBM i: A Database Modernization Guide. Rafael writes in an easy-to-read, practical style that is highly popular with his audience of IBM technology professionals.

Rafael is the Deputy IT Director - Infrastructures and Services at the Luis Simões Group in Portugal. His areas of expertise include programming in the IBM i native languages (RPG, CL, and DB2 SQL) and in "modern" programming languages, such as Java, C#, and Python, as well as project management and consultancy.


MC Press books written by Rafael Victória-Pereira available now on the MC Press Bookstore.

Evolve Your RPG Coding: Move from OPM to ILE...and Beyond Evolve Your RPG Coding: Move from OPM to ILE...and Beyond
Transition to modern RPG programming with this step-by-step guide through ILE and free-format RPG, SQL, and modernization techniques.
List Price $79.95

Now On Sale

Flexible Input, Dazzling Output with IBM i Flexible Input, Dazzling Output with IBM i
Uncover easier, more flexible ways to get data into your system, plus some methods for exporting and presenting the vital business data it contains.
List Price $79.95

Now On Sale

SQL for IBM i: A Database Modernization Guide SQL for IBM i: A Database Modernization Guide
Learn how to use SQL’s capabilities to modernize and enhance your IBM i database.
List Price $79.95

Now On Sale

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$

Book Reviews

Resource Center

  •  

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: