简体   繁体   English

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

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

I have a table set up like this: 我有一个这样的表:

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

... and so on. ... 等等。

For each unique dNum I need to find when dCode equals "foo2" and then when dChar is exactly 15 days ago. 对于每一个独特的dNum我需要找到时DCODE等于“foo2的”,然后当dChar 正是在15天前。 My problem is in getting dates from exactly 15 days ago. 我的问题是获取确切的15天前的日期。 My current code is as follows: 我当前的代码如下:

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

When I try to run this query I get the following error: "Value in date, time, or timestamp string not valid." 当我尝试运行此查询时,出现以下错误:“日期,时间或时间戳记字符串中的值无效。” What I'm even more confused about, however, is that when I put DAYS(CURRENT_DATE) - DAYS(DATE(dChar)) as a field in my SELECT statement but not in the WHERE clause, that it works just fine. 但是,令我更加困惑的是,当我将DAYS(CURRENT_DATE) - DAYS(DATE(dChar))用作我的SELECT语句中的字段而不是WHERE子句中的字段时,它工作得很好。 The following code DOES work for me: 以下代码对我有用:

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

dChar is a CHAR(25) variable, and not all values are dates, but again, that doesn't seem to affect anything when my code is not in the WHERE clause. dChar是CHAR(25)变量,并非所有值都是日期,但是同样,当我的代码不在WHERE子句中时,这似乎没有任何影响。

Can anybody help me to figure out what is going on here? 有人可以帮我弄清楚这里发生了什么吗?

What happens if you change the where code to: 如果将where代码更改为:

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

I realize this is very arcane, but it guarantees that the function is only evaluated when dcode = 'foo2' . 我意识到这非常不可思议,但是可以保证仅当dcode = 'foo2'时才评估该函数。 What might be happening is that the values are all correct when this condition is true, but problems lie elsewhere. 可能发生的情况是,当此条件为真时,值都正确,但问题出在其他地方。

Apparently, dChar values in rows where dCode equals "foo2" are valid representations of dates. 显然,其中dCode等于“ foo2”的行中的dChar值是日期的有效表示形式。 Since the select list is processed after all WHERE predicates have been applied, this does not cause any issues. 由于选择列表是在应用所有WHERE谓词之后才处理的,因此这不会引起任何问题。

If, on the other hand, you put DATE(dChar) in the WHERE clause it may encounter dChar values that can't be converted to dates. 另一方面,如果将DATE(dChar)放在WHERE子句中,则它可能会遇到无法转换为日期的dChar值。

The solution suggested by Gordon Linoff may or may not work (likely the latter), depending on how the optimizer decides to handle the CASE expression. Gordon Linoff建议的解决方案可能会或可能不会(可能是后者)起作用,这取决于优化器如何决定处理CASE表达式。

Edit: 编辑:

Your question was "what's going on?", so now you know. 您的问题是“怎么回事?”,所以现在您知道了。 If you want to go one step further and find a reliable workaround, one option would be to create a user-defined function that would gracefully handle invalid dates and use it in place of DATE() . 如果要更进一步,找到一种可靠的解决方法,一种选择是创建一个用户定义的函数,该函数可以优雅地处理无效日期,并使用它代替DATE() The function might look something like 该函数可能看起来像

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

Your WHERE clause would then look like 您的WHERE子句如下所示

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

You may need to replace '22007' with the actual SQLSTATE value that is returned to you on conversion error. 您可能需要用转换错误时返回的实际SQLSTATE值替换“ 22007”。

If you filter twice, using nested queries, you'll avoid the problem (trying to parse non date strings before they're filtered out). 如果使用嵌套查询进行两次过滤,则可以避免此问题(尝试在过滤掉非日期字符串之前解析非日期字符串)。

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

EDIT 编辑

Or, even better, reorder your query. 或者,甚至更好的是,对查询重新排序。 Convert your date into a string, not the other way around. 将您的日期转换为字符串,而不是相反。 Then indexes can be used, and non-date format values don't cause issues. 然后可以使用索引,并且非日期格式的值不会引起问题。

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

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

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