Oracle - 内联视图 - 内联应用的外部WHERE条件

时间:2017-02-09 16:35:42

标签: oracle oracle11g

我们有一个表格,其中日期以YYYYMMDD的格式存储为VARCHAR2(它是我们无法控制的遗留数据表!)。我们对表只有SELECT权限(不可编写过程/函数)。

需要从日期为>的表格中选择所有行SYSDATE。

我们对正确的格式和其他检查应用正则表达式检查,以确保该日在给定月份有效。这一切都很棒!我们的内联视图选择确保只选择具有有效日期字符串的记录。

但是,当我们申请条件检查> sysdate作为外​​部子句 - 即使内联视图选择确保没有选择此类记录,我们也会得到给定月份错误的无效日期。

在应用内联视图条件之前,查询执行似乎正在应用外部子句中的条件。感谢对行为的任何评论;并且,我们如何确保只有在满足内联条件后才能应用来自外部的条件?

数据和使用的查询:

CREATE TABLE TEST_DATA_TABLE
(
  DATESTRING  VARCHAR2(20 BYTE)
);

插入包含值的3行:

19960322 --Valid Date in past
19831131 --Invalid Date 11/31
20180224 --Valid Date > SYSDATE

有效数据选择: (其中第1条确保格式,第2条确保月份的有效日期):

SELECT datestring AS i_dob
  FROM test_data_table
 WHERE     REGEXP_LIKE (TRIM (datestring),
                        '(19|20)\d\d(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])')
       AND TRIM (datestring) <=
              TO_CHAR (
                 LAST_DAY (
                    TO_DATE (SUBSTR (TRIM (datestring), 1, 6) || '01',
                             'YYYYMMDD')),
                 'YYYYMMDD')

上面的查询工作正常并返回有效日期字符串

的有效行

选择具有日期字符串&gt;的记录SYSDATE,上面的数据是内联使用的,我们应用条件&gt; SYSDATE如下。

SELECT i_dob
  FROM (
    SELECT datestring AS i_dob
      FROM test_data_table
     WHERE     REGEXP_LIKE (TRIM (datestring),
                            '(19|20)\d\d(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])')
           AND TRIM (datestring) <=
                  TO_CHAR (
                     LAST_DAY (
                        TO_DATE (SUBSTR (TRIM (datestring), 1, 6) || '01',
                                 'YYYYMMDD')),
                     'YYYYMMDD')
) X
 WHERE TO_DATE (X.I_DOB, 'YYYYMMDD') > SYSDATE

它开始抛出错误:ORA-01839: date not valid for month specified

看起来在检查所有内联视图条件之前应用条件。

1 个答案:

答案 0 :(得分:0)

你可以通过在外部查询之前通过向其添加一个额外的rownum列来操作内联视图来解决这个问题(rownum列的存在意味着Oracle需要为它之前应用的子查询计算该列。可以进一步过滤它。

因此,您的查询将变为:

SELECT i_dob
  FROM (
    SELECT datestring AS i_dob,
           rownum rn
      FROM test_data_table
     WHERE     REGEXP_LIKE (TRIM (datestring),
                            '(19|20)\d\d(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])')
           AND TRIM (datestring) <=
                  TO_CHAR (
                     LAST_DAY (
                        TO_DATE (SUBSTR (TRIM (datestring), 1, 6) || '01',
                                 'YYYYMMDD')),
                     'YYYYMMDD')
) X
 WHERE TO_DATE (X.I_DOB, 'YYYYMMDD') > SYSDATE;

我会在你的查询中添加一条评论来解释这个专栏的存在,否则将来某些开发人员可能会认为“呃?这什么都不做;我会删除它!”。

(另外值得注意的是在12.2中,他们添加/修改了允许easier data validation的函数,当你到达12.2时这会简化你的查询!)