【问题标题】:Oracle DECODE SyntaxOracle 解码语法
【发布时间】:2017-09-27 16:44:43
【问题描述】:

问题: 我正在破译一个名为 DECODE 的函数的查询。我查看了语法(列、值、替换值、默认值),但我不明白下面的语法在做什么。

查询:

WHERE 1=1
  AND DECODE(a1.prev_start_date, NULL, 'THIS IS NOT NULL', a1.prev_end_date) IS NOT NULL 

当我添加上面的语法时,下面的行不显示,为什么?

表:

ID       prev_start_date    prev_end_date
456        2/13/2017          

【问题讨论】:

    标签: sql oracle decode


    【解决方案1】:

    代码 sn-p 的作用如下:

    如果prev_start_dateNULL,则函数返回字符串'THIS IS NOT NULL'。该字符串不是NULL,因此条件的计算结果为 TRUE。

    如果prev_start_date 不是NULL,则DECODE() 返回prev_end_date。仅当 prev_end_date 不是 NULL 时,条件才为 TRUE。

    SO:条件等价于

    (prev_start_date is null or prev_end_date is not null)
    

    显然,在您给出的示例中,prev_start_date 不是NULL,但prev_end_dateNULL - 正是不会通过过滤器的值组合。

    【讨论】:

      【解决方案2】:

      具有日期有效性的记录

      通常,当记录具有日期有效性(例如开始和结束日期)时,约定是使用between 条件,其中结束日期具有NVL 函数调用。

      主要是很多生效日期还没有结束日期。

      在您显示的开始日期附近检查NULL 满足此条件(将排除NULL)。

      关于你显示的解码语句,它

      WHERE 1=1
        AND DECODE(a1.prev_start_date, NULL, 'THIS IS NOT NULL', a1.prev_end_date) IS NOT NULL
      

      解码语句可以读作:

      "如果开始日期为 NULL,则 'THIS IS NOT NULL',否则 prev_end_date" 没有意义。

      我会有一个介于以下的条件:

      SCOTT@db>WITH test AS
        2    (SELECT hiredate prev_start_date, sysdate prev_end_date FROM emp
        3    UNION ALL
        4    SELECT to_date(NULL,'dd-mon-yyyy'), to_date(NULL,'dd-mon-yyyy') FROM dual
        5    )
        6  SELECT prev_start_date,
        7    prev_end_date
        8  FROM test t
        9  WHERE 1=1
       10  AND sysdate between t.prev_start_date and NVL(t.prev_end_date, sysdate);
      PREV_START_DATE          PREV_END_DATE            
      17-DEC-1980 12:00:00 AM  27-SEP-2017 12:40:41 PM  
      20-FEB-1981 12:00:00 AM  27-SEP-2017 12:40:41 PM  
      22-FEB-1981 12:00:00 AM  27-SEP-2017 12:40:41 PM  
      02-APR-1981 12:00:00 AM  27-SEP-2017 12:40:41 PM  
      28-SEP-1981 12:00:00 AM  27-SEP-2017 12:40:41 PM  
      01-MAY-1981 12:00:00 AM  27-SEP-2017 12:40:41 PM  
      09-JUN-1981 12:00:00 AM  27-SEP-2017 12:40:41 PM  
      09-DEC-1982 12:00:00 AM  27-SEP-2017 12:40:41 PM  
      17-NOV-1981 12:00:00 AM  27-SEP-2017 12:40:41 PM  
      08-SEP-1981 12:00:00 AM  27-SEP-2017 12:40:41 PM  
      12-JAN-1983 12:00:00 AM  27-SEP-2017 12:40:41 PM  
      03-DEC-1981 12:00:00 AM  27-SEP-2017 12:40:41 PM  
      03-DEC-1981 12:00:00 AM  27-SEP-2017 12:40:41 PM  
      23-JAN-1982 12:00:00 AM  27-SEP-2017 12:40:41 PM  
      
      
      14 rows selected. 
      

      NULL 被排除在结果集中。

      【讨论】:

      • between 与 oracle 日期一起使用通常是一个坏主意,因为 oracle 日期包含时间。
      • 你从哪里得到这个想法的?与start_dateend_date 的约定是使用between 运算符的条件?这是不正确的(告诉我们你在哪里看到了这样的约定),并且在许多情况下会导致错误的结果。惯例是start_date 包含在与该行相关的时间间隔中,但end_date排除。常见的约定是具有dt >= start_date AND dt < end_date 之类的条件 - 注意严格的不等式。
      • @mathguy 它在 oracle 应用程序代码中无处不在。
      • @Dan Bracuk 我的回答应该更加细致入微。对于生效日期,应该查看应用程序如何填充这些列以及它们背后的业务规则。
      猜你喜欢
      • 1970-01-01
      • 2013-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多