如何替换多个相同的子查询?

时间:2019-12-19 10:31:02

标签: sql oracle

我确实有这样的查询,其中调用了多个总和子查询。 With子句似乎在这里不起作用。

select 
    a.id, 
    a.balance as main_balance, 
    (select sum(amount) from sub_account sa where sa.account_id = a.id) as sub_account_sum, 
    a.balance - (select sum(amount) from sub_account sa where sa.account_id = a.id) as diff
from accounts a 
inner join sub_account sa on sa.account_id = a.id
where a.balance != (select sum(amount) from sub_account sa where sa.account_id = a.id)
and a.balance - (select sum(amount) from sub_account sa where sa.account_id = a.id) < 5000
and a.balance - (select sum(amount) from sub_account sa where sa.account_id = a.id) > -5000
and (select count(*) from sub_account sa where sa.account_id = a.id) > 1

子查询(select sum(amount) from sub_account sa where sa.account_id = a.id)被调用5次。基本上,我想在每个地方用外观更好的东西代替它。

4 个答案:

答案 0 :(得分:2)

为什么WITH子句不起作用?试试看。我删除了最后一条语句(在where子句中带有count(*),因为您正在执行内部联接,因此无论如何都不会满足条件。

WITH sub_account_sum_by_acct AS
(select account_id, sum(amount) as sub_account_sum from sub_account sa group by account_id)
SELECT 
    a.id, 
    a.balance as main_balance, 
    sa.sub_account_sum, 
    a.balance - sa.sub_account_sum as diff
FROM accounts a 
     JOIN sub_account_sum_by_acct sa on sa.account_id = a.id
where a.balance != sa.sub_account_sum
and a.balance - sa.sub_account_sum < 5000
and a.balance - sa.sub_account_sum > - 5000

答案 1 :(得分:1)

您可以使用窗口函数代替子查询:

select
    id,
    balance,
    sub_account_sum
from (
    select 
        a.id, 
        a.balance as main_balance, 
        sum(amount) over(partition by sa.account_id) as sub_account_sum,
        count(*) over(partition by sa.account_id) as sub_account_cnt
    from accounts a 
    inner join sub_account sa on sa.account_id = a.id
) t
where 
    balance != sub_account_sum
    and abs(a.balance - sub_account_sum) < 5000
    and sub_account_cnt > 1

答案 2 :(得分:0)

您还可以使用以下功能。我保持与您的SQL相同的格式,只是删除了多个子查询并使它们保持功能。逻辑与您的SQL相同。

 WITH FUNCTION sa_acc(val VARCHAR2) RETURN VARCHAR2 IS
 lv_val varchar2(20);
 BEGIN
   SELECT SUM(amount) into lv_val
   FROM sub_account sa
   WHERE sa.account_id = val;

   return lv_val;
 END;


SELECT a.id,
       a.balance AS main_balance,
       sa_acc(a.id) AS sub_account_sum,
       a.balance - (sa_acc(a.id)) AS diff
FROM accounts a
INNER JOIN sub_account sa ON sa.account_id = a.id
WHERE a.balance != (sa_acc(a.id))
AND a.balance - (sa_acc(a.id)) < 5000
AND a.balance - (sa_acc(a.id)) >-5000
AND (
    SELECT
        COUNT(*)
    FROM
        sub_account sa
    WHERE
        sa.account_id = a.id
) > 1

答案 3 :(得分:0)

    With sum_addi as
    (select sa.account_id , sum(amount) as summ from sub_account sa 
    having count(*) > 1 
and  sum(amount) < 5000 
and  sum(amount) > -5000)
    select 
        a.id, 
        a.balance as main_balance, 
     b.summ  as sub_account_sum, 
        a.balance - b.summ as diff
    from accounts a 
    inner join sum_addi b on a.account_id = b.id
where balance <> b.summ;