【问题标题】:SQL JOIN Condition time format errorSQL JOIN 条件时间格式错误
【发布时间】:2017-11-20 23:27:56
【问题描述】:

我正在编写使用 VBA 访问“绿屏”AS400 IBM iSERIES 的 SQL 代码,并且我正在通过 ADODB 连接进行连接(如果您需要有关连接或 SQL 版本的更多信息,请告诉我,我是SQL 初学者)。

现在我的代码运行得很好,但是我想在最后一个 LEFT JOIN 中添加另一个“AND”条件,这样代码只考虑存在于 [ (PO.STKDT- PO.ACTDT)

所以我想添加类似的内容:

AND ( date(timestamp((PO.STKDT + 19000000) concat '000000')) - date(timestamp((PO.ACTDT + 19000000) concat '000000')) ) <40 

代码在没有这个条件的情况下运行良好,但是当我添加这个条件时,它给我一个错误“SQL0181:日期、时间或时间戳字符串中的值无效”。

任何帮助都可以解决 AND 条件错误

请注意,我将“TIMESTAMP”和“DATE”附加到 STKDT 和 ACTDT 日期列,以便将其从格式 1171119 转换为 2017 年 11 月 19 日。而且我有一个参数可以正确地使用这种格式提取列数据。

感谢您的帮助!

这是我的完整代码:

SELECT X.ITNBR AS ITEM, X.ITDSC AS DESCRIPTION,
X.CRUS AS CREATE_USER, X.INVFG AS INV_FLAG ,
C1.PURPR AS PO_PRICE, C2.STDUC AS STD_COST, 
A.HOUSE AS WHS, A.WHSLC AS WHSLOCATION ,
A.VNDNR AS VENDR,VN.VNAME AS VENDOR_NAME ,
VN.VNAMA, A.MOHTQ AS QTY_ON_HAND,
A.MPUPQ AS QTY_ON_PURCHASE ,A.MALQT AS QTY_ALLOCATED,
(A.MOHTQ+A.MPUPQ-A.MALQT) AS QTY_AVAILABLE,
( (A.MOHTQ+A.MPUPQ-A.MALQT) * C2.STDUC ) AS INV_COST,
K.KIORDCNT AS KB_CARDS, K.KICQTY AS KB_QTY,
K.KICTYP AS KB_TYPE, COUNT( PO.ITNBR ) AS DATA_COUNT ,
AVG(PO.STKPR) AS AVG_PO_PRICE, 
CAST(AVG( date(timestamp((PO.STKDT + 19000000) concat '000000')) - date(timestamp((PO.ACTDT + 19000000) concat '000000')) ) AS DECIMAL(50,2) ) AS AVG_LEADTIME,
SUM(PO.QTYOR) AS ALL_QTY_ORDERED,MIN(PO.QTYOR) AS MIN_QTY_ORDERED,
CAST(AVG(PO.QTYOR) AS DECIMAL(50,2) ) AS AVG_QTY_ORDERED, 
MAX(PO.QTYOR) AS MAX_QTY_ORDERED


FROM SIM.ENT X 
                LEFT JOIN SIM.ITEM A ON (A.ITNBR=X.ITNBR) 
                LEFT JOIN SIM.ITMR C1 ON (C1.ITNBR=A.ITNBR) 
                LEFT JOIN SIM.ITMV C2 ON (C2.ITNBR=A.ITNBR) 
                LEFT JOIN SIM.VENN VN ON (VN.VNDNR=A.VNDNR) 
                LEFT JOIN SIM.KBIM K  ON (K.KIITEM=A.ITNBR AND K.KIHOUSE=A.HOUSE)
                LEFT JOIN SIM.POIT PO ON (PO.ITNBR=A.ITNBR AND PO.HOUSE=A.HOUSE AND PO.VNDNR=A.VNDNR)
                AND PO.STAIC !=99 
                AND PO.ACTDT between '" & Range("AA1") & "' and  '" & Range("AB1") & "' ***AND MYTIMECONDITIONHERE***
            WHERE X.ITNBR != 'TEST%'


GROUP BY X.ITNBR, X.ITDSC,X.CRUS,X.INVFG, C1.PURPR, C2.STDUC 
        ,A.HOUSE, A.VNDNR,VN.VNAME, VN.VNAMA, A.WHSLC
        ,A.MOHTQ,A.MPUPQ,A.MALQT,K.KIORDCNT, K.KICQTY, K.KICTYP`

【问题讨论】:

  • 您不能使用 SQL 访问绿屏,对吧?您使用它来查询数据库。对于 IBM i,该数据库很可能是 DB2 for i。

标签: join conditional-statements ibm-midrange datetime-format db2-400


【解决方案1】:

当您只想查看日期时,为什么要转换为时间戳?

要将数字 CYYMMDD 转换为实际日期,您需要构建一个包含“YYYY-MM-DD”的字符串...所以您需要这样的东西:

select date(                                                
            substring(char(dec(1171120,7) + 19000000),1,4)  
            concat '-' concat                               
            substring(char(dec(1171120,7) + 19000000),5,2)  
            concat '-' concat                               
            substring(char(dec(1171120,7) + 19000000),7,2)  
           ) as theDate                                     
from sysibm.sysdummy1                                       

与其在语句中转换它,不如构建一个转换它的 UDF。或者更好的是,下载这样的UDF我推荐iDate

【讨论】:

  • 感谢 Charles,我尝试了您提供的代码 .. 它正确地提取了列数据作为参数。但是当我将它用作条件时,它给了我上面提供的相同错误。
  • @MrKen 您可能有一个包含无效日期的列。想到零……但 1170229 也会失败。
【解决方案2】:

首先,我会将您的 PO 过滤条件从联接子句(它们不是联接条件)移到 where 子句中。这只是语义上的事情,根本不会影响查询。它只是让事情更容易理解,因为所有过滤条件都在一个地方,而所有连接条件都在另一个地方。然后我会使用timestamp_format 将数字日期更改为timestamp 值。然后将timestamp 转换为自 0001 年 1 月 1 日以来的天数。您可以减去这些并与 40 进行比较。这是根据我的建议修改的查询。

SELECT X.ITNBR AS ITEM, 
       X.ITDSC AS DESCRIPTION,
       X.CRUS AS CREATE_USER, 
       X.INVFG AS INV_FLAG,
       C1.PURPR AS PO_PRICE, 
       C2.STDUC AS STD_COST, 
       A.HOUSE AS WHS, 
       A.WHSLC AS WHSLOCATION,
       A.VNDNR AS VENDR,
       VN.VNAME AS VENDOR_NAME,
       VN.VNAMA, 
       A.MOHTQ AS QTY_ON_HAND,
       A.MPUPQ AS QTY_ON_PURCHASE,
       A.MALQT AS QTY_ALLOCATED,
       (A.MOHTQ+A.MPUPQ-A.MALQT) AS QTY_AVAILABLE,
       ((A.MOHTQ+A.MPUPQ-A.MALQT) * C2.STDUC) AS INV_COST,
       K.KIORDCNT AS KB_CARDS, 
       K.KICQTY AS KB_QTY,
       K.KICTYP AS KB_TYPE, 
       COUNT(PO.ITNBR) AS DATA_COUNT ,
       AVG(PO.STKPR) AS AVG_PO_PRICE, 
       CAST(AVG(date(timestamp((PO.STKDT + 19000000) concat '000000')) -
           date(timestamp((PO.ACTDT + 19000000) concat '000000'))) 
           AS DECIMAL(50,2)) AS AVG_LEADTIME,
       SUM(PO.QTYOR) AS ALL_QTY_ORDERED,
       MIN(PO.QTYOR) AS MIN_QTY_ORDERED,
       CAST(AVG(PO.QTYOR) AS DECIMAL(50,2)) AS AVG_QTY_ORDERED, 
       MAX(PO.QTYOR) AS MAX_QTY_ORDERED

FROM SIM.ENT X 
    LEFT JOIN SIM.ITEM A ON (A.ITNBR=X.ITNBR) 
    LEFT JOIN SIM.ITMR C1 ON (C1.ITNBR=A.ITNBR) 
    LEFT JOIN SIM.ITMV C2 ON (C2.ITNBR=A.ITNBR) 
    LEFT JOIN SIM.VENN VN ON (VN.VNDNR=A.VNDNR) 
    LEFT JOIN SIM.KBIM K  ON (K.KIITEM=A.ITNBR AND K.KIHOUSE=A.HOUSE)
    LEFT JOIN SIM.POIT PO 
        ON (PO.ITNBR=A.ITNBR AND PO.HOUSE=A.HOUSE AND PO.VNDNR=A.VNDNR)

WHERE X.ITNBR != 'TEST%'
    AND PO.STAIC != 99 
    AND PO.ACTDT between '" & Range("AA1") & "' and  '" & Range("AB1") & "' 
    AND days(timestamp_format(PO.STKDT + 19000000, 'YYYYMMDD')) - 
        days(timestamp_format(PO.ACTDT + 19000000, 'YYYYMMDD')) < 40

GROUP BY X.ITNBR, X.ITDSC,X.CRUS,X.INVFG, C1.PURPR, C2.STDUC 
        ,A.HOUSE, A.VNDNR,VN.VNAME, VN.VNAMA, A.WHSLC
        ,A.MOHTQ,A.MPUPQ,A.MALQT,K.KIORDCNT, K.KICQTY, K.KICTYP

【讨论】:

  • 感谢 jmarkmurphy,我刚刚尝试了两次我的初始工作代码(没有添加 40 天的额外条件),一次是在 LEFT JOIN 处出现条件,另一次是在WHERE 子句分别给了我不同的 633421 和 246321 计数。看起来 WHERE 子句不仅限制了 PO 表,还限制了所有表的结果。但我只想包含 LEFT JOIN 的条件。
【解决方案3】:

您可能需要检查 DAYS 函数。如果您的原始字段是有效的日期字段,您的表达式将很简单:

DAYS(PO.STKDT) - DAYS(PO.ACTDT) < 40

按照您的方式首先通过日期/时间戳进行转换稍微复杂一些,但应该仍然有效。另见:Calculating how many days are between two dates in DB2?

【讨论】:

  • 感谢 Richard,这给了我一个错误 SQL0171:函数 DAYS 的参数 1 无效
猜你喜欢
  • 2018-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-10
  • 2012-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多