无法使CASE工作以进行NULL替换。

时间:2014-03-01 11:31:38

标签: mysql sql

我的代码示例如下:

我想查找已经开始的合同,并且可能有也可能没有结束日期。如果结束日期晚于今天,或者尚未指定(NULL /空),那么很好。

SELECT 
   ID, BeginDate, EndDate,
CASE
   WHEN EndDate IS NULL 
    THEN curdate()+1
END as FinishDate
FROM 
    contracts
WHERE 
    (id=1) AND
    (CURDATE() BETWEEN BeginDate and FinishDate);

但我得到了

#1054 - Unknown column 'FinishDate' in 'where clause

我错过了什么?

2 个答案:

答案 0 :(得分:2)

这是因为FinishDate不是原始表的列,因此其标识符的范围仅限于ORDER BY子句;它不能在WHERE子句中使用。

有几种方法可以解决此问题。最简单的方法是将表达式复制到WHERE子句中:

SELECT 
   ID, BeginDate, EndDate,
CASE
   WHEN EndDate IS NULL 
    THEN curdate()+1
END as FinishDate
FROM 
    contracts
WHERE 
    (id=1) AND
    (CURDATE() BETWEEN (CASE WHEN EndDate IS NULL THEN curdate()+1 END) and FinishDate);

注意:大多数RDBMS都有一个特殊的运算符来提供空替换表达式。在MS SQL Server中COALESCEISNULL

SELECT 
   ID, BeginDate, EndDate,
   ISNULL(EndDate, curdate()+1) as FinishDate
FROM 
    contracts
WHERE 
    (id=1) AND
    (CURDATE() BETWEEN ISNULL(EndDate, curdate()+1) and FinishDate);

答案 1 :(得分:0)

在MySQL中,您实际上可以将条件移动到having子句:

SELECT ID, BeginDate, EndDate,
       (CASE WHEN EndDate IS NULL 
             THEN curdate()+1
        END) as FinishDate
FROM contracts
WHERE (id=1)
HAVING (CURDATE() BETWEEN BeginDate and FinishDate);

这是一个MySQL扩展,允许您使用select中定义的列别名进行过滤。顺便问一下,你确定逻辑是正确的吗?你真的希望它是:

SELECT ID, BeginDate, EndDate, COALESCE(EndDate, curdate() + 1) as FinishDate

不同之处在于,当NULL有值时,您的版本会将FinishDate放入EndDate。如果可用,此版本使用EndDate,如果不可用,则替换“明天”。