• 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
    Raz-Lee Security

    Start your Road to Zero Trust!

    Firewall Network security, controlling Exit Points, Open DB’s and SSH. Rule Wizards and graphical BI.

    Request Demo

    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

  • Public Preview For Watson Code Assistant for i Available Soon
  • COMMON Youth Movement Continues at POWERUp 2025
  • IBM Preserves Memory Investments Across Power10 And Power11
  • Eradani Uses AI For New EDI And API Service
  • Picking Apart IBM’s $150 Billion In US Manufacturing And R&D
  • FAX/400 And CICS For i Are Dead. What Will IBM Kill Next?
  • Fresche Overhauls X-Analysis With Web UI, AI Smarts
  • Is It Time To Add The Rust Programming Language To IBM i?
  • Is IBM Going To Raise Prices On Power10 Expert Care?
  • IBM i PTF Guide, Volume 27, Number 20

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