• The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
Menu
  • The Four Hundred
  • Subscribe
  • Media Kit
  • Contributors
  • About Us
  • Contact
  • Let One Row Represent A Group, Take Three

    October 27, 2015 Ted Holt

    Faithful reader Bill Cisne sent me an email with an SQL SELECT query. No comment, no explanation, just code. Bill had figured out how to use a lateral join to solve a problem and was kind enough to share his success with me. I have been aware of lateral joins for some time, but have not found a need for them in my work. Today I revisit a problem to illustrate one way that lateral joins can be useful.

    LATERAL is a type of for-each loop within a query. For each row that a SELECT statement (the “outer” query) returns, the system executes a second (or inner) query. The power of LATERAL is that the inner query may refer to columns from the outer query. Michael Sansoterra mentioned LATERAL a long while back in this august publication.

    To illustrate the workings of LATERAL, let’s return to an example I’ve used before: retrieving only one row per group. Let’s list an unshipped sales order with information from only one line item–the one with the earliest entry time.

    Here’s the raw detail data:

    Order  Line   Qty  Shipped Balance  Price  Time
      101    1     10       10       0   4.00  2015-10-21-08.14.06
      101    2     12        0      12   1.00  2015-10-21-11.15.32
      101    3      8        0       8   3.00  2015-10-28-14.14.37
      102    1     10        5       5   2.00  2015-10-21-10.05.12
      103    3      5        0       5   1.10  2015-10-21-14.37.25
      104    1      5        5       0   3.50  2015-10-21-14.58.21
      105    1      4        4       0   5.00  2015-10-21-15.30.44
      105    2      6        0       6   2.00  2015-10-21-15.30.45
    

    Notice that there are two incomplete lines for order 101.

    Here’s the query:

    select h.OrderNo,
          substr(char(h.OrderDate),1,10) as OrderDate,
          d.LineNo,
          (d.QtyOrdered - d.QtyShipped) as Balance,
          d.Price,
          dec((d.QtyOrdered - d.QtyShipped) * d.Price,7,2)
                as Extended,
          substr(char(d.crttime), 1, 16) as TimeEntered
     from SalesOrdH as h,
     lateral (select *
                from SalesOrdD as x
               where h.orderno = x.orderno
                 and x.QtyShipped < x.QtyOrdered
               order by x.crttime
               fetch first row only) as d
    

    To deepen my understanding, I’ve been working through the examples in Michael R. Jones’ fabulous ebook, Converting RPG to Set Based SQL (Part 1: Input Operations). Michael uses a slightly different syntax, which works just as well as the previous example.

    select h.OrderNo,
           h.CustNo,
           substr(char(h.OrderDate),1,10) as OrderDate,
           d.LineNo,
           (d.QtyOrdered - d.QtyShipped) as Balance,
           d.Price,
           dec((d.QtyOrdered - d.QtyShipped) * d.Price,7,2)
                 as Extended,
           substr(char(d.crttime), 1, 16) as TimeEntered
      from SalesOrdH as h
     cross join lateral (select *
                           from SalesOrdD as x
                          where h.orderno = x.orderno
                            and x.QtyShipped < x.QtyOrdered
                       order by x.crttime
                          fetch first row only) as d
    

    Both queries return the same report:

    Order  Customer  Order date Line   Balance  Price  Extended Time
      101  80112300  2015-10-20   2         12   1.00     12.00 2015-10-21-11.15
      102  25000300  2015-10-20   1          5   2.00     10.00 2015-10-21-10.05
      103  65888800  2015-10-21   3          5   1.10      5.50 2015-10-21-14.37
      105  42221700  2015-10-21   2          6   2.00     12.00 2015-10-21-15.30
    

    To understand this, let’s begin with the outer query. It selects a few columns from the order header table and a few columns (some of which are calculated) from a lateral expression, i.e. an inner query. For each sales order header row, the query engine runs the inner query to retrieve one row from the sales order detail table. This inner query looks for the earliest-dated detail row which has not been completely shipped.

    Notice that the nested query refers to a table in the outer query (correlation name h). That’s that power of LATERAL that I mentioned above.

    LATERAL was added to DB2 some 11 years ago. Don’t you agree that it’s about time I got around to mastering it?

    RELATED STORIES

    For i Scalar Function Performance Considerations

    Let One Row Represent a Group, Take 2

    Let One Row Represent a Group

    More V5R3 SQL Enhancements

    Share this:

    • Share on Reddit (Opens in new window) Reddit
    • Share on Facebook (Opens in new window) Facebook
    • Share on LinkedIn (Opens in new window) LinkedIn
    • Share on X (Opens in new window) X
    • Email a link to a friend (Opens in new window) Email

    Tags:

    Sponsored by
    JAMS Software

    One Scheduler. IBM i, Windows, Linux, and More.

    IBM i teams trust JAMS to schedule and orchestrate jobs across every platform in their environment. Centralized visibility, cross-platform dependency management, and alerts that reach the right person before the business feels it.

    Fewer than 5% of IBM i shops run IBM i only. The rest are managing cross-platform dependencies — often without a clear picture of how they connect. JAMS draws that map, enforces those dependencies automatically, and gives your team a single place to monitor, manage, and recover when something goes wrong.

    If you are running hundreds of CL scripts and custom RPG processes, bring them as-is. JAMS runs them exactly as they do today — except now they are visible, monitored, and part of an orchestrated workflow instead of scattered across folders only one person knows about.

    No consumption-based pricing. No surprise bills when your workload spikes. You pay based on how many machines JAMS talks to — that’s it.

    Learn More → https://jamsscheduler.com/lp/ibm-i

    Share this:

    • Share on Reddit (Opens in new window) Reddit
    • Share on Facebook (Opens in new window) Facebook
    • Share on LinkedIn (Opens in new window) LinkedIn
    • Share on X (Opens in new window) X
    • Email a link to a friend (Opens in new window) Email

    Sponsored Links

    Connectria:  Need help managing your IBM i? Trust us as an extension of your IT department.
    HelpSystems:  How do you use IBM i? Your peers want to know! Take the survey >
    Rocket Software:  Mobile app development and deployment solution for IBM i. Download FREE trial!

    Using Adopted Authority Wisely Questions About AES Encryption In RPG, DB2 for i, And The Web

    Leave a ReplyCancel reply

Volume 15, Number 22 -- October 27, 2015
THIS ISSUE SPONSORED BY:

ProData Computer Services
WorksRight Software
United Computer Group, Inc.

Table of Contents

  • Using Adopted Authority Wisely
  • Let One Row Represent A Group, Take Three
  • Questions About AES Encryption In RPG, DB2 for i, And The Web

Content archive

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

Recent Posts

  • Inside The Encryption Key Management Changes In IBM i 7.6
  • FalconStor Moved To The Blue Lagoon, And Is Poised For Growth Because Of It
  • Guru: Claude’s SQL Tip
  • Astera Makes Extracting Legacy Report Data an AI Specialty
  • IBM i PTF Guide, Volume 28, Number 27
  • Welcoming The New IBM i Chief Architect And Other New Top Brass
  • A Deep Dive Into That Power S1112 Entry Power11 Server
  • Guru: Beyond Three-Part Naming – Running SQL Across Remote IBM i Systems
  • How IBM Bolstered IBM i Resilience In The Summer Tech Refreshes
  • IBM i PTF Guide, Volume 28, Number 26

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