简体   繁体   中英

iSeries SQL - Use Previous Record Value in JOIN criteria

In my example, I am trying to retrieve records from a transaction file based on the previous calendar work date. The work dates are in a file called CALNDR, the transactions in a file called TRNHST. The logic would be to use the CURRENT_DATE to set the cursor on CALNDR, then retrieve the previous work date which will be used to join to TRNHST. This would be simple enough if done in RPG but I am at a loss with SQL. Thanks, for any input you can provide.

CALNDR

TRNHST

This is even more simple with SQL probably.
You may uncomment the commented out block to run it as is to check.

/*
WITH 
  CALNDR (DT, IS_WORK) AS
  (
    VALUES
      (CURRENT_DATE - 1 DAY, 'N')
    , (CURRENT_DATE - 2 DAY, 'Y')
    , (CURRENT_DATE - 3 DAY, 'Y')
  )
, TRNHST (DT, SOME_COL) AS 
  (
    VALUES
      (CURRENT_DATE - 1 DAY, 1)
    , (CURRENT_DATE - 2 DAY, 2)
    , (CURRENT_DATE - 3 DAY, 3)
  )  
*/
SELECT CURRENT_DATE AS CDT, T.*
FROM
(
  SELECT MAX (DT) DT
  FROM CALNDR
  WHERE DT < CURRENT_DATE AND IS_WORK = 'Y'
) C
JOIN TRNHST T ON T.DT = C.DT

Honestly, if "prior working day" for a given date is something you need. You should consider adding such a column to your calendar table.

While you're at it, might as well add a "next working day".

One of the biggest benefits to a calendar table is the ability to pre-calculate such columns. Thus, greatly simplifying your statements.

Not real sure what LAG does as I have never used it. So, here's another solution using a cross join:

WITH calendar (workdt) AS (
    VALUES (CAST('2022-01-01' AS date)),
           (CAST('2022-02-01' AS date)),
           (CAST('2022-03-01' AS date)),
           (CAST('2022-04-01' AS date))
    ),
orders (orderno, orderdt) AS (
    VALUES (1, CAST('2022-01-15' AS date)),
           (2, CAST('2022-02-15' AS date)),
           (3, CAST('2022-03-15' AS date)),
           (4, CAST('2022-04-15' AS date))
    )
SELECT * 
FROM orders a
CROSS JOIN LATERAL (SELECT max(workdt) prevdt FROM calendar WHERE workdt < a.orderdt) b

The cross join only returns a single row for each record in the calendar file, and that row contains the largest work date less than the order date. LATERAL just lets the sub-query access columns from the outer query.

write an SQL function named calndr_prevWorkDate that returns the previous work date.

Then use that function in the WHERE clause of an SQL SELECT statement to select records from the TRNHST table:

select     a.*  
from       trnhst a                    
where      a.trandate = calndr_prevWorkDate( )  

Here is the SQL function.

CREATE OR REPLACE FUNCTION calndr_prevWorkDate(                
startDate   date default current date )                        
RETURNS     date                                               
language sql                                                   
specific    calndrf1                                           
SET OPTION  datfmt = *ISO,   DLYPRP = *YES, DBGVIEW = *SOURCE, 
            USRPRF = *OWNER, DYNUSRPRF = *OWNER, COMMIT = *CHG 
BEGIN                                                          
                                                               
declare     vCalDate  date ;                                   
declare     vSqlCode decimal(5,0) default 0 ;                  
declare     sqlCode int default 0 ;                            
declare     sqlState char(5) default ' ' ;                     
declare     vSqlState char(5) default ' ' ;                    
declare     vErrText varchar(256) default '' ;                 
                                                               
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION                      
begin                                                          
SET     vSqlCode  = SQLCODE ;                                  
SET     vSqlState = SQLstate ;                                 
get     diagnostics exception 1 vErrText = message_text ;      
end ;                                                          
                                                               
select      a.caldate                                
into        vCalDate                                 
from        calndr a                                 
where       a.caldate < startDate                    
            and dayofweek(a.caldate) not in ( 1, 7)  
order by    a.caldate desc                           
fetch first row only ;                               
                                                     
return      vCalDate ;                               
END                                                  

if all u need is the previous date from a table you can use something like that

select * from TRNHST where Trans_Date = ( select calendar_Date from CALNDR where calendar_Date < current date order by calendar_Date desc limit 1 )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM