【问题标题】:Comparing DB2 DATES - IBM i dates not compatible with DB2 dates SQL比较 DB2 日期 - IBM i 日期与 DB2 日期 SQL 不兼容
【发布时间】:2018-02-12 22:40:43
【问题描述】:

我正在尝试创建一个报告,显示延迟的订单、本月到期的订单、下个月到期的订单等。使用 DB2 SQL 从 IBM i 服务器 (AS/400) 提取数据。但是,我遇到了比较运算符的问题。我有一个潜在的解决方案,但它太乏味了,它会使我的代码显着更长并且很容易出错。

例如,我按请求日期拉客户订单:

  SELECT C6D0NB /* REQUEST DATE */                   
    FROM MBC6REP /* CUSTOMER ORDER FILE */             
   WHERE C6DCCD = '1' /* ONLY ORDERS, NOT QUOTES */   
ORDER BY C6D0NB DESC /* DATES DESCENDING ORDER */  

导致:

 Request 
 date    
118/08/28 
118/06/29 
118/06/15 
118/06/07 
....
117/07/21 
117/06/14 
117/04/14 
117/03/01  

因此,这个“请求日期”(C6D0NB) 字段在我的 ERP 系统 (Infor XA) 中被标记为“日期”格式。我可以使用比较运算符来使用静态比较(例如,在 2018 年 1 月 1 日和 2018 年 1 月 15 日之间,含):

   SELECT C6D0NB /* REQUEST DATE */                     
     FROM MBC6REP /* CUSTOMER ORDER FILE */               
    WHERE C6DCCD = '1' /* ONLY ORDERS, NOT QUOTES */ AND 
          C6D0NB >= '1180101' AND                              
          C6D0NB <= '1180115'                                  
 ORDER BY C6D0NB DESC /* DATES DESCENDING ORDER */    

结果:

  Request 
  date    
 118/01/15 
 118/01/15 
 118/01/12 
 118/01/12 
 ....
 118/01/03 
 118/01/03 
 118/01/03 
 118/01/02  

但是,当我想使用“当前日期”功能时,我遇到了错误。当我查询时:

SELECT CURRENT DATE   
FROM SYSIBM.SYSDUMMY1 

我收到了预期的:

CURRENT DATE
02/12/18  

我可以按预期使用 DAY、MONTH、YEAR 函数:

SELECT DAY(CURRENT DATE)
FROM SYSIBM.SYSDUMMY1   

返回:

DAY 
12 

但是,我不能将两者结合起来:

  SELECT C6D0NB /* REQUEST DATE */                    
    FROM MBC6REP /* CUSTOMER ORDER FILE */              
   WHERE C6DCCD = '1' /* ONLY ORDERS, NOT QUOTES */ AND
         C6D0NB >= CURRENT DATE                              
ORDER BY C6D0NB DESC /* DATES DESCENDING ORDER */   

这给了我错误:

 Comparison operator >= operands not compatible. 

如果我尝试将 MONTH 与“请求日期”一起使用,

  SELECT MONTH(C6D0NB) /* REQUEST DATE */           
    FROM MBC6REP /* CUSTOMER ORDER FILE */            
   WHERE C6DCCD = '1' /* ONLY ORDERS, NOT QUOTES */  
ORDER BY C6D0NB DESC /* DATES DESCENDING ORDER */ 

我收到此错误:

Argument 1 of function MONTH not valid. 

如何创建动态报告以查询例如当月内的所有日期?我可以运行以下代码,但是非常繁琐:

    SELECT C6D0NB /* REQUEST DATE */              
    FROM MBC6REP /* CUSTOMER ORDER FILE */               
    WHERE C6DCCD = '1' /* ONLY ORDERS, NOT QUOTES */ AND
    MONTH(TO_DATE((CONCAT(
             CONCAT(
             (CONCAT(SUBSTRING(C6D0NB,4,2), '/')),
             (CONCAT(SUBSTRING(C6D0NB,6,2), '/'))),
             SUBSTRING(C6D0NB,2,2))), 'MM/DD/YY')) = MONTH(CURRENT DATE) AND
    YEAR(TO_DATE((CONCAT(
             CONCAT(
             (CONCAT(SUBSTRING(C6D0NB,4,2), '/')),
             (CONCAT(SUBSTRING(C6D0NB,6,2), '/'))),
             SUBSTRING(C6D0NB,2,2))), 'MM/DD/YY')) = YEAR(CURRENT DATE)  
    ORDER BY C6D0NB DESC /* DATES DESCENDING ORDER */ 

这真的是最简洁的编码方式吗?

谢谢!

【问题讨论】:

    标签: sql date db2 comparison-operators


    【解决方案1】:

    C6D0NB 实际上不是日期列,它是一个数值列,其值被您的 ERP 解释为 CYYMMDD 格式的日期。

    IBM i 及其早期版本 iSeries 和 AS/400 长期以来一直支持真正的日期类型。

    不幸的是,它们并没有在许多较旧的应用程序中使用...

    最佳解决方案,使用 UDF 将数值转换为实际日期。您可以自己编写,或下载 Alan Campin 的 iDate 工具...

    那么你就可以简单地做...

      SELECT C6D0NB /* REQUEST DATE */                    
        FROM MBC6REP /* CUSTOMER ORDER FILE */              
       WHERE C6DCCD = '1' /* ONLY ORDERS, NOT QUOTES */ AND
             idate(C6D0NB,'*CYMD') >= CURRENT DATE                              
    ORDER BY C6D0NB DESC /* DATES DESCENDING ORDER */ 
    

    实际上,从性能的角度来看,最好将日期转换为 CYYMMDD 数字。 Alan的包里就有这样的功能……

      SELECT C6D0NB /* REQUEST DATE */                    
        FROM MBC6REP /* CUSTOMER ORDER FILE */              
       WHERE C6DCCD = '1' /* ONLY ORDERS, NOT QUOTES */ AND
             C6D0NB >= convertToiDate(CURRENT DATE, '*CYMD')                              
    ORDER BY C6D0NB DESC /* DATES DESCENDING ORDER */ 
    

    这允许使用 C6D0NB 上的索引...

    或者,您可以创建“日期”或“日历”表。除了使用它从数字日期转换为实际日期类型之外......它对于许多其他基于集合的操作很有用......在任何数据库中。

    【讨论】:

      【解决方案2】:

      看 CYYMMDD 日期并不漂亮,但可以使用内置的 varchar_format 函数来完成。

      我从位置 2 开始比较,因为那是“1”所在的位置,这是 21 世纪。

      select * from mytable 
      where mycyymmdd date =
      substring( varchar_format(current timestamp,'CCYY/MM/DD'), 2)                            
      

      【讨论】:

        【解决方案3】:

        为了方便查找,从here复制:


        由于没有一个变体适合我的需要,所以我推出了自己的变体。

        就这么简单:

        select * from yourschema.yourtable where yourdate = int(CURRENT DATE - 1 days) - 19000000;

        days 这个东西是闰年感知的,可以很好地满足大多数需求。

        同样的方式days 可以转换为monthsyears。 不需要像VARCHAR_FORMAT/TIMESTAMP_FORMAT这样的重炮。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-09-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多