在Oracle中避免相关子查询

时间:2012-05-23 15:13:45

标签: sql database oracle subquery oracle9i

在Oracle 9.2.0.8中,我需要为另一个字段返回一个特定字段(LAB_SEQ)最大的记录集(它是一个顺序VARCHAR数组'0001','0002'等) (WO_NUM)。要选择最大值,我尝试按降序排序并选择第一行。我在StackOverflow上可以找到的所有内容都表明,执行此操作的唯一方法是使用相关子查询。然后我在外部查询的WHERE子句中使用此最大值来获取每个WO_NUM所需的行:

SELECT lt.WO_NUM, lt.EMP_NUM, lt.LAB_END_DATE, lt.LAB_END_TIME
FROM LAB_TIM lt WHERE lt.LAB_SEQ = (
   SELECT LAB_SEQ FROM (
      SELECT lab.LAB_SEQ FROM LAB_TIM lab WHERE lab.CCN='1' AND MAS_LOC='1'
          AND lt.WO_NUM = lab.WO_NUM ORDER BY ROWNUM DESC
   ) WHERE ROWNUM=1
)

但是,这会返回lt.WO_NUM错误的无效标识符。研究表明,ORacle 8只允许相关子查询达到一个深度,并建议重写以避免子查询 - 这一点无法完成选择最大值的讨论。任何有助于执行此声明的帮助将不胜感激。

2 个答案:

答案 0 :(得分:3)

您的相关子查询需要类似

SELECT lt.WO_NUM, lt.EMP_NUM, lt.LAB_END_DATE, lt.LAB_END_TIME
FROM LAB_TIM lt WHERE lt.LAB_SEQ = (
   SELECT max(lab.LAB_SEQ)
     FROM LAB_TIM lab 
    WHERE lab.CCN='1' AND MAS_LOC='1'
      AND lt.WO_NUM = lab.WO_NUM 
  )

由于您使用的是Oracle 9.2,因此使用相关子查询可能会更有效。我不确定谓词lab.CCN='1' AND MAS_LOC='1'在当前查询中做了什么,所以我不太确定如何将它们转换为分析函数方法。 LAB_SEQWO_NUM的组合在LAB_TIM中不是唯一的吗?您是否需要在CCNMAS_LOC添加谓词,以便为每个WO_NUM获取一个唯一的行?或者您是否使用这些谓词来减少输出中的行数?基本方法将类似于

SELECT *
  FROM (SELECT lt.WO_NUM, 
               lt.EMP_NUM, 
               lt.LAB_END_DATE, 
               lt.LAB_END_TIME,
               rank() over (partition by wo_num
                                order by lab_seq desc) rnk
          FROM LAB_TIM lt)
   WHERE rnk = 1

但我不清楚是否需要将CCNMAS_LOC添加到分析函数的ORDER BY子句中,或者是否需要将它们添加到WHERE条款。

答案 1 :(得分:0)

这是相关子查询更好的一种情况,特别是如果表上有索引。但是,应该可以将相关子查询重写为连接。

我认为以下内容是等效的,没有相关的子查询:

SELECT lt.WO_NUM, lt.EMP_NUM, lt.LAB_END_DATE, lt.LAB_END_TIME
FROM (select *, rownum as r
      from LAB_TIM lt
     ) lt join
     (select wo_num, max(r) as maxrownum
      from (select LAB_SEQ, wo_num, rownum as r
            from LAB_TIM lt
            where lab.CCN = '1' AND MAS_LOC = '1'
           ) 
     ) ltsum
     on lt.wo_num = ltsum.wo_num and
        lt.r = ltsum.maxrownum

我对Oracle如何使用ORDER BY之类的rownums感到有点不确定。