Microsoft Query 正确显示数据但不会 return 数据到 Excel- 错误 SQ20448

Microsoft Query displaying data correctly but won't return data to Excel- Error SQ20448

早上好,

我有一个半功能 SQL 查询,用于将数据从 IBM AS/400 提取到 Microsoft Excel。数据在 Microsoft Query 中正确显示,但是当我单击 "Return Data" 将数据 return 更改为 Excel 时,我收到以下错误消息:

[IBM][System i Access ODBC Driver][DB2 for i5/OS]SQ20448 - Expression not 
valid using format string specified for TIMESTAMP_FORMAT.

基本上,我的代码加入了一些文件来为我提供项目信息,并使用日期删除重复项,以便我可以获得最新的交易。

我对其他正常运行的文件使用了几乎相同的代码,所以我怀疑我的原始数据中可能存在格式不正确的日期,这会导致在将 IBM 日期转换为 Microsoft 兼容日期时出现错误TO_DATE 函数。 我知道我的日期转换工作正常,因为 IBM 日期是实际日期。

我的问题是,我如何在异常中编写代码以忽略格式不正确的数据,或者我如何 return 格式不正确的数据以便我可以将异常写入我的代码?

这是我的代码(希望评论有帮助):

SELECT xh.ITNBR, yh.VNDNR, zh.VN35VM, yh.BUYNO, xh.Create_Date -- Item #, Vendor #, Vendor Name, Buyer, Create_Date
  FROM
   (SELECT PO_IH.ITNBR, -- Item #
           max(TO_DATE((CONCAT(
         CONCAT(
         (CONCAT(SUBSTRING(PO_MH.ACTDT,4,2), '/')),
         (CONCAT(SUBSTRING(PO_MH.ACTDT,6,2), '/'))),
         SUBSTRING(PO_MH.ACTDT,2,2))), 'MM/DD/YY')) as Create_Date -- Converts IBM date format to work with Microsoft Query
      FROM POHISTI as PO_IH, POHSTM as PO_MH 
     WHERE PO_IH.ORDNO = PO_MH.ORDNO AND
           (TO_DATE((CONCAT(
         CONCAT(
         (CONCAT(SUBSTRING(PO_MH.ACTDT,4,2), '/')),
         (CONCAT(SUBSTRING(PO_MH.ACTDT,6,2), '/'))),
         SUBSTRING(PO_MH.ACTDT,2,2))), 'MM/DD/YY')) = 
           (SELECT MIN((TO_DATE((CONCAT(
         CONCAT(
         (CONCAT(SUBSTRING(PO_MH.ACTDT,4,2), '/')),
         (CONCAT(SUBSTRING(PO_MH.ACTDT,6,2), '/'))),
         SUBSTRING(PO_MH.ACTDT,2,2))), 'MM/DD/YY'))) -- All of this chaos basically removes duplicate information and converts IBM date
              FROM POHSTM as PO_MH2
             WHERE PO_MH.ORDNO = PO_MH2.ORDNO AND
                   PO_MH.ACTDT NOT LIKE '0%' AND -- Removes dates that start with 0 (i.e. IBM's way of saying "no date")
                   PO_MH.ACTDT NOT LIKE '9%') -- Removes dates from 20th century
  GROUP BY PO_IH.ITNBR) xh
 LEFT JOIN 
   (SELECT PO_IH2.ITNBR, -- Item #
           PO_IH2.BUYNO, -- Buyer
           PO_IH2.VNDNR, -- Vendor
           (TO_DATE((CONCAT(
         CONCAT(
         (CONCAT(SUBSTRING(PO_MH2.ACTDT,4,2), '/')),
         (CONCAT(SUBSTRING(PO_MH2.ACTDT,6,2), '/'))),
         SUBSTRING(PO_MH2.ACTDT,2,2))), 'MM/DD/YY')) as Create_Date
    FROM POHISTI as PO_IH2, POHSTM as PO_MH2
   WHERE PO_IH2.ORDNO = PO_MH2.ORDNO AND
         PO_MH2.ACTDT NOT LIKE '0%' AND -- Removes dates that start with 0 (i.e. IBM's way of saying "no date")
         PO_MH2.ACTDT NOT LIKE '9%') yh -- Removes dates from 20th century
      ON xh.ITNBR = yh.ITNBR AND xh.Create_Date = yh.Create_Date
LEFT JOIN VENNAML0 zh -- Vendor Name
      ON yh.VNDNR = zh.VNDRVM

这是 Microsoft Query 中的输出:

ITNBR           VNDNR   VN35VM          BUYNO   CREATE_DATE

A-FUL           76      HOLLAND COMP    SUSY    2016-12-06 00:00:00.000000
A-MINI          76      HOLLAND COMP    SUSY    2016-11-28 00:00:00.000000
A-SHIMBOX       76      HOLLAND COMP    SUSY    2014-10-16 00:00:00.000000
A-001           76      HOLLAND COMP    SUSY    2016-12-19 00:00:00.000000
A-002           76      HOLLAND COMP    SUSY    2016-12-19 00:00:00.000000
....

正如我所说,信息在 Microsoft Query 中显示完美,但是当我 return 将其显示为 Excel 时,出现上述错误。我尝试使用上面的 "NOT LIKE" 语句来处理两个最常见的错误,但我不知道如何找到其他错误。

我真的不在乎我是否得到坏数据,只要它转储到 Excel。到那时我可以纠正它。但我怀疑如果 Microsoft Query 不能转换日期,它不会 return 数据到 Excel.

谢谢。

您有一个格式类似于 CYYMMDD 的数字字段。这是 IBM i 世界中的一种常见日期格式,其中 C 是世纪代码(0=>19、1=>20、2=>21、...、9=>28)。这是因为大多数十进制日期在 Y2K 修复之前以 2 位数字的压缩十进制格式存储。由于格式的配置,压缩十进制总是有奇数位的空间,但大多数日期被定义为 (6,0) (length,decimal places)。这在磁盘上为日期左侧的一个额外数字留出了空间,人们可以将日期定义为 (7,0) 而无需更改记录中数据的格式。因此 7 位数的日期是 Y2K 的结果。 Synon 是我所知道的第一家在他们的 2E 代码生成器中这样做的公司。它很受欢迎,格式无处不在。它甚至进入了 IBM 操作系统。

所以当 SQL 将其转换为 CHAR 时,像 0951107 这样的日期看起来像 951107,而当 SQL 将 1171107 转换为 CHAR 时,它看起来像 1171107。不幸的是,NOT LIKE '9%'在某些时候会不可靠,因为前导 9 可能是 1990 纪元日期的第一个非零数字,也可能是 2800 纪元日期。更糟糕的是,1900 年的 CHAR 日期可以从 1-9 开始。例如,日期 1985/12/05 在 CYYMMDD 数字格式中看起来像 0851205。这将转换为 851205。因此,在处理日期时,您需要使用 DIGITS 将数字转换为 CHAR,这样您就不会丢失前导 0 字符。并且您需要测试 0 的日期字段,它实际上是 0000000(不是 00/00/00,即使它是使用 EDITC(Y) 格式化时的样子)。

这是一个正在发生的事情的例子:

create table datetest
  (decdt       decimal(7,0));
insert into datetest
  values (0), (941107), (1170304), (1000101);

select substr(decdt,4,2) || '/' || 
       substr(decdt,6,2) || '/' || 
       substr(decdt,2,2), 
       decdt 
from datetest;

结果:

  /  /      0
10/7 /41    941,107
03/04/17    1,170,304
01/01/00    1,000,101

我打赌你的程序 TO_DATE() 没有正确处理无效日期,因为它们几乎肯定会被传递。如果你在substr函数中使用digits,你会得到更理智的东西。

select substr(digits(decdt),4,2) || '/' || 
       substr(digits(decdt),6,2) || '/' || 
       substr(digits(decdt),2,2), 
       decdt
from datetest

结果:

00/00/00    0
11/07/94    941,107
03/04/17    1,170,304
01/01/00    1,000,101

请注意,月日和年部分现在都在正确的位置,您只需编码 0 日期,这意味着没有日期。在任何情况下,函数 to_date() 都需要检测无效日期并忽略它,或者将其设置为可用的日期,例如 0001-01-01null.