• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • Dealing With A MIN/MAX Quirk

    March 15, 2016 Ted Holt

    The MIN and MAX functions have been a part of SQL since the beginning. A database-kind-of-guy-or-gal would think that anything so established would be stable to the point of boredom, but a database-kind-of-guy-or-gal would be wrong. MIN and MAX don’t even work the same way in all implementations of SQL, and to top it off, they have a quirk that I come upon occasionally.

    MIN and MAX began as aggregate functions. As such, they locate the minimum and maximum non-null values within a column across a set of rows. On this, everyone in the database world is in agreement. The controversy arises with the use of MIN and MAX as scalar functions.

    Assume a physical file of manufacturing transactions. It has separate packed-decimal date and time fields. The date is seven digits in CYYMMDD format. The time is six digits in HHMMSS format. I want the last date a manufacturing order was completed (i.e., the manufacturing status is 40) for each item.

    select mxItem, max(mxDate)
    from mfgtrans
    where mxStatus = 40
    group by mxItem
    order by mxItem
    

    Now for the quirk. Suppose I want the last date and time each operation was completed. This would be a no-brainer if the date and time were stored in a single timestamp column, but many readers of this august publication work with database tables that predate the introduction of the timestamp data type.

    Here’s one way that doesn’t work.

    select mxItem, max(mxDate, mxTime)
     from mfgtrans
    where mxStatus = 40
    group by mxItem
    order by mxItem
    

    If you try to run this query, DB2 for i responds with message SQL0122 (Column MXDATE or expression in SELECT list not valid.) In other words, the MAX expression is not a grouping column.

    You might be tempted to omit GROUP BY.

    select mxItem, max(mxDate, mxTime)
     from mfgtrans
    where mxStatus = 40
    order by mxItem
    

    This query runs, but it has two problems. First, when used as scalar functions, MIN and MAX return the smallest and largest values in a list. Here the MAX function compares the date and time and returns the greater of the two, which is not what we want. Some systems avoid this problem by using MIN and MAX only as aggregate functions and defining other functions for scalar use. Oracle, for example, has LEAST and GREATEST scalar functions.

    But the bigger problem is that the query no longer groups by item number, so let’s get back to the original challenge.

    Here’s one way to find the last date and time a manufacturing order was completed.

    select mxItem, max(mxDate * 1000000 + mxtime)
     from mfgtrans
    where mxStatus = 40
    group by mxItem
    order by mxItem
    

    This makes a 13-digit number of the date and time. The system has no trouble finding the maximum value of the expression for each item.

    Here’s another method.

    select mxItem,
     max(digits(mxDate) concat digits(mxtime))
     from mfgtrans
    where mxStatus = 40
    group by mxItem
    order by mxItem
    

    I prefer this to the previous method under the general theory that string operations tend to tax the system less than arithmetic ones do.

    I could also convert the date and time into a timestamp field, but I am not courageous and adventurous enough to hack my way through the expression that would be required for that approach.

    Here’s a different approach.

    with Temp as
     (select m.*, row_number() over
      (partition by mxItem
      order by mxItem,
      mxDate desc,
      mxTime desc) as Row_Nbr
      from mfgtrans as m
      where mxStatus = 40)
    
    select mxItem, mxDate, mxTime
     from Temp
     where Row_Nbr = 1
     order by mxItem
    

    I’ve used OLAP features instead of aggregate functions. The system sorts the data by item number, descending date and descending time.

    PARTITION BY is similar to GROUP BY. In RPG terms, you might think of this as a control break over the item number. The ROW_NUMBER function assigns a sequential number–named ROW_NBR–to each row in the result set, and because the data is partitioned on item number, renumbering restarts at 1 with each item.

    This result set makes up the TEMP common table expression. The main query (the second SELECT) examines the value of ROW_NBR to pick out only the first row per item.

    The advantage of this approach is the lack of derived (calculated) columns.

    How about that? One way to find the minimum or maximum doesn’t use the MIN and MAX functions. Who’d a thunk it?

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Tags:

    Sponsored by
    Manta Technologies

    The Leader in IBM i Education!
    Need training on anything i?
    Manta is all you need.

    130 courses and competency exams on:
    · IBM i operations
    · System Management and Security
    · IBM i Programming Tools
    · Programming in RPG, COBOL, CL, Java
    · Web Development

    SQL, DB2, QueryProduct features:
    · Runs in every popular browser
    · Available 24/7/365
    · Free Student Reference Guides
    · Free Student Administration
    · Concurrent User License
    · Built-In IBM i Simulator

    You can download our 200-page catalog and take sample sessions at MantaTech.com

    Share this:

    • Reddit
    • Facebook
    • LinkedIn
    • Twitter
    • Email

    Sponsored Links

    COMMON:  2016 Annual Meeting & Expo, May 15 - 18, in New Orleans! Great Power Systems event!
    System i Developer:  RPG & DB2 Summit - March 22-24 in Dallas. Check out the session grid!
    NGS:  Webinar: Getting from ? to ! with NGS-IQ - April 5. RSVP Now!

    More Jobs Lost Than Found During IBM Resource Action Verizon Outlines Disturbing AS/400 Breach At Water District

    Leave a Reply Cancel reply

Volume 16, Number 06 -- March 15, 2016
THIS ISSUE SPONSORED BY:

Bug Busters Software Engineering
ProData Computer Services
WorksRight Software

Table of Contents

  • Getting Started With IBM i And .Net XMLSERVICE Connectivity
  • Dealing With A MIN/MAX Quirk
  • Generating An Insert Script From Existing Data

Content archive

  • The Four Hundred
  • Four Hundred Stuff
  • Four Hundred Guru

Recent Posts

  • IBM Unveils Manzan, A New Open Source Event Monitor For IBM i
  • Say Goodbye To Downtime: Update Your Database Without Taking Your Business Offline
  • i-Rays Brings Observability To IBM i Performance Problems
  • Another Non-TR “Technology Refresh” Happens With IBM i TR6
  • IBM i PTF Guide, Volume 27, Number 18
  • Will The Turbulent Economy Downdraft IBM Systems Or Lift It?
  • How IBM Improved The Database With IBM i 7.6
  • Rocket Celebrates 35th Anniversary As Private Equity Owner Ponders Sale
  • 50 Acres And A Humanoid Robot With An AI Avatar
  • IBM i PTF Guide, Volume 27, Number 17

Subscribe

To get news from IT Jungle sent to your inbox every week, subscribe to our newsletter.

Pages

  • About Us
  • Contact
  • Contributors
  • Four Hundred Monitor
  • IBM i PTF Guide
  • Media Kit
  • Subscribe

Search

Copyright © 2025 IT Jungle