在WHERE子句中使用别名


67

我有一个查询,该查询旨在向我显示表A中最近更新不够的任何行。(每行应在“ month_no”之后的2个月内更新。):

SELECT A.identifier
     , A.name
     , TO_NUMBER(DECODE( A.month_no
             , 1, 200803 
             , 2, 200804 
             , 3, 200805 
             , 4, 200806 
             , 5, 200807 
             , 6, 200808 
             , 7, 200809 
             , 8, 200810 
             , 9, 200811 
             , 10, 200812 
             , 11, 200701 
             , 12, 200702
             , NULL)) as MONTH_NO
     , TO_NUMBER(TO_CHAR(B.last_update_date, 'YYYYMM')) as UPD_DATE
  FROM table_a A
     , table_b B
 WHERE A.identifier = B.identifier
   AND MONTH_NO > UPD_DATE

WHERE子句中的最后一行会导致“ ORA-00904无效标识符”错误。不用说,我不想在WHERE子句中重复整个DECODE函数。有什么想法吗?(接受了修复程序和解决方法...)

Answers:


114

这不可能直接实现,因为按时间顺序,WHERE发生SELECT之前,这始终是执行链中的最后一步。

您可以进行子选择并对其进行过滤:

SELECT * FROM
(
  SELECT A.identifier
    , A.name
    , TO_NUMBER(DECODE( A.month_no
      , 1, 200803 
      , 2, 200804 
      , 3, 200805 
      , 4, 200806 
      , 5, 200807 
      , 6, 200808 
      , 7, 200809 
      , 8, 200810 
      , 9, 200811 
      , 10, 200812 
      , 11, 200701 
      , 12, 200702
      , NULL)) as MONTH_NO
    , TO_NUMBER(TO_CHAR(B.last_update_date, 'YYYYMM')) as UPD_DATE
  FROM table_a A
    , table_b B
  WHERE A.identifier = B.identifier
) AS inner_table
WHERE 
  MONTH_NO > UPD_DATE

有趣的信息从评论中移了出来:

应该不会影响性能。Oracle不需要在应用外部条件之前具体化内部查询-Oracle将考虑在内部转换此查询并将谓词下推到内部查询中,如果这样做具有成本效益,则可以这样做。–贾斯汀·凯夫Justin Cave)


16
 SELECT A.identifier
 , A.name
 , TO_NUMBER(DECODE( A.month_no
         , 1, 200803 
         , 2, 200804 
         , 3, 200805 
         , 4, 200806 
         , 5, 200807 
         , 6, 200808 
         , 7, 200809 
         , 8, 200810 
         , 9, 200811 
         , 10, 200812 
         , 11, 200701 
         , 12, 200702
         , NULL)) as MONTH_NO
 , TO_NUMBER(TO_CHAR(B.last_update_date, 'YYYYMM')) as UPD_DATE
FROM table_a A, table_b B
WHERE .identifier = B.identifier
HAVING MONTH_NO > UPD_DATE

1
HAVING才是真正的答案。HAVING是计算列,如条款检查COUNTMAX并在其他表达式SELECT查询,因为它过滤最终获取的数据。
乔治·迪米特里亚迪斯

11

或者您可以在HAVING子句中使用别名


4
这将是一种有趣的方法,您能提供任何代码吗?
rob5408

关于适用位置的规则相同,因此这不是解决方案。
Alexey

我受困于MySQL(5.5),不知道这是否适用于Oracle。但: SELECT CONCAT(names, surname) AS x FROM clients HAVING x LIKE '%a%' 有效,但SELECT CONCAT(names, surname) AS x FROM clients WHERE x LIKE '%a%'失败(“'where子句'中的未知列'x'”)
fr13d 2015年

2

就像您可以选择的另一种方法一样:

WITH inner_table AS
(SELECT A.identifier
    , A.name
    , TO_NUMBER(DECODE( A.month_no
      , 1, 200803 
      , 2, 200804 
      , 3, 200805 
      , 4, 200806 
      , 5, 200807 
      , 6, 200808 
      , 7, 200809 
      , 8, 200810 
      , 9, 200811 
      , 10, 200812 
      , 11, 200701 
      , 12, 200702
      , NULL)) as MONTH_NO
    , TO_NUMBER(TO_CHAR(B.last_update_date, 'YYYYMM')) as UPD_DATE
  FROM table_a A
    , table_b B
  WHERE A.identifier = B.identifier)

    SELECT * FROM inner_table 
    WHERE MONTH_NO > UPD_DATE

您也可以为队列创建一个永久视图,然后从视图中进行选择。

CREATE OR REPLACE VIEW_1 AS (SELECT ...);
SELECT * FROM VIEW_1;

1

可以有效地定义一个可以在SELECT,WHERE和其他子句中使用的变量。

子查询不一定允许对引用的表列进行适当的绑定,但是OUTER APPLY允许。

SELECT A.identifier
     , A.name
     , vars.MONTH_NO
     , TO_NUMBER(TO_CHAR(B.last_update_date, 'YYYYMM')) as UPD_DATE
FROM table_a A
     , table_b B ON A.identifier = B.identifier
OUTER APPLY (
   SELECT
        -- variables
        MONTH_NO = TO_NUMBER(DECODE( A.month_no
                     , 1, 200803 
                     , 2, 200804 
                     , 3, 200805 
                     , 4, 200806 
                     , 5, 200807 
                     , 6, 200808 
                     , 7, 200809 
                     , 8, 200810 
                     , 9, 200811 
                     , 10, 200812 
                     , 11, 200701 
                     , 12, 200702
                     , NULL))
) vars
WHERE vars.MONTH_NO > UPD_DATE

Syed Mehroz Alam的荣誉。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.