SQL使用NVL替换NULL,无法正确检查where子句中的替换值

时间:2013-02-26 17:44:52

标签: sql informix nvl

我正在运行查询,以便在起始日期(< =)当前日期之前显示消息,并且to_date在当前日期之后(>)。

如果to_dateNULL,那么我使用NVL方法给它一个值并检查where子句,如果它不是null - 即用户为它提供了值 - 然后它应该使用该值并检查where子句中的条件。

select a.id,
       title,
       body,
       NVL(a.to_date, '9999-12-31 23:59:59') as todate,
       cr_date
from   a,
       b
where  a.cust_id = 20 and
       a.body_id = b.body_id and
       a.from_date <= current and 
       a.to_date > current

但是当我为我的数据库运行此查询时,我只获得用户输入to_date时的结果。当to_date为null并且其值为'9999-12-31 23:59:59'时,我不会得到结果 - 即: 它失败了a.to_date&gt; where子句中的当前条件,因此不返回这些条目。 to_date为NULL时的值被'9999-12 ...'正确替换,但where条件'&gt;当前'失败。

我想在查询中进行替换而不是单独的语句。从逻辑上讲,我认为它应该可行,但出于某种原因,我在某个地方出错了。还不确定这是否会影响查询执行,但在创建表时,to_date的默认值设置为NULL。

你能帮我解决这个问题。感谢

3 个答案:

答案 0 :(得分:2)

您需要阅读NULL值比较 - http://www.w3schools.com/sql/sql_null_values.asp

NULL和'SOME_DATE'无法与=,&lt;或&lt;&gt;进行比较运营商。与这些运算符的比较总是错误的。

因此,您的条件“a.to_date&gt; current”将始终为false,并且永远不会返回任何具有NULL to_date的行。

如果您需要退回,则需要更改查询:

where  a.cust_id = 20 and
       a.body_id = b.body_id and
       a.from_date <= current and 
       ((a.to_date > current) OR (a.to_date IS NULL))

希望这有帮助。

编辑:

根据您的评论,我想澄清一下SQL执行中有一个优先顺序。在这种情况下,将首先评估FROM子句,然后是WHERE,最后是SELECT子句。您在SELECT子句中执行的任何操作仅影响输出的“显示”方式。它不会更改计算的行数。在您的示例中,where子句已经消除了NULL值,因此SELECT子句中的NVL()替换实际上是多余的,因为输出中永远不会有任何NULL值。

答案 1 :(得分:2)

我不是100%明确你的问题,但听起来你希望在WHERE条款中评估你的替代日期,即使你没有包括NVL()。你试过这个:

select a.id,
   title,
   body,
   NVL(a.to_date, to_date('9999-12-31 23:59:59', 'YYYY-MM-DD HH24:MI:SS')) as todate,
   cr_date
from   a,
   b
where  a.cust_id = 20 and
   a.body_id = b.body_id and
   a.from_date <= current and 
   NVL(a.to_date, to_date('9999-12-31 23:59:59', 'YYYY-MM-DD HH24:MI:SS')) > current

答案 2 :(得分:0)

基本问题是'display labels'或'column aliases'不能在查询体(WHERE子句)中使用。你可以使用子查询解决这个问题:

SELECT id, title, body, to_date, cr_date
  FROM (SELECT a.id,
               a.title,
               b.body,
               NVL(a.to_date, '9999-12-31 23:59:59') AS to_date,
               b.cr_date
          FROM a JOIN b ON a.body_id = b.body_id
         WHERE a.cust_id = 20
           AND a.from_date <= CURRENT
       ) AS t
 WHERE to_date > CURRENT

这可以避免重复NVL表达。

请注意,AS中的todate与WHERE中的to_date之间存在冲突。我还建议在查询使用多个表时识别每个列来自哪个表(如内部查询那样,但外部查询没有)。我通常使用单字母别名表;这次,别名是不必要的,因为给出的表名是单字母名称。

此查询计划可能与单级查询相同。当然,您可以使用SET EXPLAIN进行检查。