我有一个像这样设置的表:
**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子句中时,这似乎不会影响任何事情。
有人可以帮我弄清楚这里发生了什么吗?
答案 0 :(得分:0)
如果您将where
代码更改为:
WHERE dCode = 'foo2' AND
(case when dcode = 'foo2'
then DAYS(CURRENT_DATE) - DAYS(DATE(dChar))
end) = 15
我意识到这是非常神秘的,但它保证仅在dcode = 'foo2'
时评估该功能。可能发生的事情是,当这个条件成立时,这些值都是正确的,但问题在于其他地方。
答案 1 :(得分:0)
显然,dChar
等于“foo2”的行中的dCode
值是日期的有效表示。由于在已应用所有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值。
答案 2 :(得分:0)
如果使用嵌套查询过滤两次,则可以避免此问题(尝试在过滤掉非日期字符串之前解析它们)。
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)