【问题标题】:DB2 SQL: Function works in SELECT statement, but not in WHERE clauseDB2 SQL:函数在 SELECT 语句中起作用,但在 WHERE 子句中不起作用
【发布时间】:2016-10-26 21:45:28
【问题描述】:

我有一张这样的桌子:

**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 子句中时,这似乎不会影响任何事情。

谁能帮我弄清楚这里发生了什么?

【问题讨论】:

    标签: sql db2


    【解决方案1】:

    如果您将where 代码更改为:

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

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

    【讨论】:

    • 我已经尝试了您的代码,并且收到了相同的错误声明。进一步查看数据,我发现有时 dCode = 'foo2' dChar 为空白。
    • @jve3 。 . .我很惊讶这个版本不起作用。在大多数数据库中,case 有助于规避此类问题。
    【解决方案2】:

    显然,dChar 行中dCode 等于“foo2”的值是日期的有效表示。由于选择列表是在所有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
    

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

    【讨论】:

    • 您是正确的,dChar 不一定是日期,但是当 dCode = 'foo2' 时,它应该是可以转换为日期的字符串。我注意到在某些情况下 dCode = 'foo2' 但 dChar 为空白。如您所料,Gordon Linoff 的回答并没有解决我的问题。
    【解决方案3】:

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

    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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-27
      • 2019-09-22
      • 1970-01-01
      • 2010-12-28
      • 2013-05-03
      相关资源
      最近更新 更多