繁体   English   中英

DB2 SQL:函数在SELECT语句中起作用,但在WHERE子句中不起作用

[英]DB2 SQL: Function works in SELECT statement, but not in WHERE clause

我有一个这样的表:

**dNum | dType | dCode | dChar**
    1  |  blah |  foo  | xxxx
    1  |  blah |  foo2 | 10/11/2016
    2  |  blah |  foo  | xxxx
    2  |  blah |  foo2 | 10/19/2016

... 等等。

对于每一个独特的dNum我需要找到时DCODE等于“foo2的”,然后当dChar 正是在15天前。 我的问题是获取确切的15天前的日期。 我当前的代码如下:

SELECT dNum
,dChar
FROM thing.table boo
WHERE dCode = 'foo2' AND
      DAYS(CURRENT_DATE) - DAYS(DATE(dChar)) = 15

当我尝试运行此查询时,出现以下错误:“日期,时间或时间戳记字符串中的值无效。” 但是,令我更加困惑的是,当我将DAYS(CURRENT_DATE) - DAYS(DATE(dChar))用作我的SELECT语句中的字段而不是WHERE子句中的字段时,它工作得很好。 以下代码对我有用:

SELECT dNum
,dChar
,DAYS(CURRENT_DATE) - DAYS(DATE(dChar)) AS TEST1
FROM thing.table boo
WHERE dCode = 'foo2'

dChar是CHAR(25)变量,并非所有值都是日期,但是同样,当我的代码不在WHERE子句中时,这似乎没有任何影响。

有人可以帮我弄清楚这里发生了什么吗?

如果将where代码更改为:

WHERE dCode = 'foo2' AND
      (case when dcode = 'foo2'
            then DAYS(CURRENT_DATE) - DAYS(DATE(dChar))
       end) = 15

我意识到这非常不可思议,但是可以保证仅当dcode = 'foo2'时才评估该函数。 可能发生的情况是,当此条件为真时,值都正确,但问题出在其他地方。

显然,其中dCode等于“ foo2”的行中的dChar值是日期的有效表示形式。 由于选择列表是在应用所有WHERE谓词之后才处理的,因此这不会引起任何问题。

另一方面,如果将DATE(dChar)放在WHERE子句中,则它可能会遇到无法转换为日期的dChar值。

Gordon Linoff建议的解决方案可能会或可能不会(可能是后者)起作用,这取决于优化器如何决定处理CASE表达式。

编辑:

您的问题是“怎么回事?”,所以现在您知道了。 如果要更进一步,找到一种可靠的解决方法,一种选择是创建一个用户定义的函数,该函数可以优雅地处理无效日期,并使用它代替DATE() 该函数可能看起来像

create function to_date_safe (str varchar(20)) 
returns date 
deterministic 
no external action contains sql 
begin 
  declare continue handler for sqlstate '22007' -- on conversion error
    return null; 
  return date(str); 
end

您的WHERE子句如下所示

WHERE dCode = 'foo2' AND
  DAYS(CURRENT_DATE) - DAYS(to_date_safe(dChar)) = 15

您可能需要用转换错误时返回的实际SQLSTATE值替换“ 22007”。

如果使用嵌套查询进行两次过滤,则可以避免此问题(尝试在过滤掉非日期字符串之前解析非日期字符串)。

SELECT
    *
FROM
(
    SELECT
        dNum,
        dChar
    FROM
        thing.table boo
    WHERE
        dCode = 'foo2'
        AND dChar <> ''
)
    foo2
WHERE
    DAYS(CURRENT_DATE) - DAYS(DATE(dChar)) = 15

编辑

或者,甚至更好的是,对查询重新排序。 将您的日期转换为字符串,而不是相反。 然后可以使用索引,并且非日期格式的值不会引起问题。

WHERE
        dCode = 'foo2'
    AND dChar = CHAR(CURRENT_DATE - 15 DAYS)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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