如何用非相关子查询替换相关子查询?

时间:2014-01-05 14:33:46

标签: sql performance subquery informix

由于correlated subquery,我的查询效果不佳,我希望将其替换为wiz non-correlated subquery。如何做到这一点:

我的查询:

select a.emp_num, a.name , b.cont_date 
from main_emp a INNER JOIN main_cont b
ON a.emp_num = b.emp_num AND a.calc_year = b.calc_year 

join 
(
    select emp_num,calc_year, max(bb.cont_date) AS max_date from main_cont bb
    GROUP BY emp_num,calc_year
)   bb_max
on a.emp_num =  bb_max.emp_num and a.calc_year = bb_max.calc_year and b.cont_date = bb_max.max_date

where
( 0 = ( select count(*) from main_serv x where x.emp_num = a.emp_num and x.calc_year = a.calc_year ) 
    or b.cont_date >  ( select max(y.ser_date) from main_serv y where y.emp_num = a.emp_num and y.calc_year = a.calc_year) ) -- The problem here
and a.calc_year = 2015
order by 1

现在我要转换此子查询:

  ( 0 = ( select count(*) from main_serv x where x.emp_num = a.emp_num and x.calc_year = a.calc_year ) 
        or b.cont_date >  ( select max(y.ser_date) from main_serv y where y.emp_num = a.emp_num and y.calc_year = a.calc_year) ) 

像这样加入:

 join 
    (
        select emp_num,calc_year, max(bb.cont_date) AS max_date from main_cont bb
        GROUP BY emp_num,calc_year
    )   bb_max
    on a.emp_num =  bb_max.emp_num and a.calc_year = bb_max.calc_year and b.cont_date = bb_max.max_date

但我不知道怎么做,因为我有((0 =(subquery) OR (subquery))

2 个答案:

答案 0 :(得分:2)

我相信WHERE子句的这一部分

( 0 = ( select count(*) from main_serv x where x.emp_num = a.emp_num and x.calc_year = a.calc_year ) 
    or b.cont_date >  ( select max(y.ser_date) from main_serv y where y.emp_num = a.emp_num and y.calc_year = a.calc_year) )

可以呈现为

  

main_serv中没有行   OR
  main_serv中没有ser_date等于或大于b.cont_date的行。

我相信析取的第二部分涵盖了完整的条件,因为当main_serv中没有行时,肯定没有与条件的第二部分匹配的行,并且如果有任何行main_serv,它将决定结果的条件的第二部分。所以,我会像这样重写整个析取部分:

not exists (
  select *
  from main_serv as x
  where x.emp_num = a.emp_num
    and x.calc_year = a.calc_year
    and x.ser_date >= b.cont_date
)

此子查询仍然与主查询相关,但它不会执行任何聚合,并且总体上可能比您的版本有所改进。

答案 1 :(得分:1)

像这样:

SELECT 
  a.emp_num, 
  a.name, 
  b.cont_date 
FROM main_emp a 
INNER JOIN main_cont b ON a.emp_num = b.emp_num AND a.calc_year = b.calc_year 
INNER JOIN 
(
    SELECT emp_num,calc_year, max(bb.cont_date) AS max_date 
    from main_cont bb
    GROUP BY emp_num,calc_year
)   bb_max
on a.emp_num =  bb_max.emp_num and a.calc_year = bb_max.calc_year 
                               and b.cont_date = bb_max.max_date
INNER JOIN 
( 
   SELECT emp_num, calc_year, count(*) AS count, max(ser_date) AS MaxDate 
   from main_serv 
   WHERE calc_year IS NOT NULL
   GROUP BY emp_num, calc_year
) x ON x.count = 0 OR b.cont_date > x.MaxDate 
    AND x.emp_num = a.emp_num 
    AND x.calc_year = a.calc_year
where a.calc_year = 2015
order by 1