早上好,
我有一个半功能的SQL查询,用于将数据从IBM AS / 400提取到Microsoft Excel中。数据在Microsoft Query中正确显示,但是当我点击"返回数据"要将数据返回到Excel,我收到以下错误消息:
[IBM][System i Access ODBC Driver][DB2 for i5/OS]SQ20448 - Expression not
valid using format string specified for TIMESTAMP_FORMAT.
基本上,我的代码加入了一些文件来向我提供商品信息,并使用日期删除重复项,以便我可以获得最新的交易。
我对其他正常运行的文件使用了几乎相同的代码,因此我怀疑原始数据中可能存在格式不正确的日期,这会在使用TO_DATE将IBM日期转换为Microsoft兼容日期时导致错误功能。 我知道我的日期转换正常,因为IBM日期是实际日期。
我的问题是,如何在异常中编码以忽略格式错误的数据,或者如何返回格式不正确的数据以便我可以在代码中编写异常? < / p>
这是我的代码(希望评论有用):
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中完美显示,但当我将其返回到Excel时,我得到了上述错误。我尝试使用上面的&#34; NOT LIKE&#34;处理两个最常见错误的陈述,但我对如何找到其他错误感到茫然。
如果我收到错误的数据,我真的不在乎,只要它转储到Excel中。那时我可以纠正它。但是我怀疑如果Microsoft Query无法转换日期,它就不会将数据返回给Excel。
感谢。
答案 0 :(得分:1)
您有一个格式为CYYMMDD的数字字段。这是IBM i世界中的常见日期格式,其中C是世纪代码(0 =&gt; 19,1 => 20,2 =&gt; 21,...,9 =&gt; 28)。这是因为大多数小数日期以压缩十进制格式存储,在Y2K补救之前有2位数年份。由于格式的配置,打包小数始终具有奇数位数的空间,但大多数日期定义为(6,0)(长度,小数位)。这使得磁盘上的空间在日期左侧有一个额外的数字,人们可以将日期定义为(7,0)而不改变记录中数据的格式。因此,7位数的日期是由Y2K诞生的。 Synon是我所知道的第一家在他们的2E代码生成器中做到这一点的公司。它很受欢迎,格式无处不在。它甚至进入了IBM操作系统。
因此当SQL将其转换为CHAR时,像0951107这样的日期看起来像951107,当SQL将1171107转换为CHAR时,它看起来像1171107.不幸的是,NOT LIKE '9%'
在某些时候是不可靠的,因为那个领先9可能是1990年代日期的第一个非零数字,也可能是2800年代的日期。更糟糕的是,1900年的约会可能会从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()
没有正确处理无效日期,因为它们几乎肯定会被传递。如果您在digits
函数中使用substr
,您将获得更加理智的内容。
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-01
或null
。