实际项目(报表功能)遇到的sql优化(存储过程、临时表和with的选择)

    因为报表要从别的表加载数据,由于表很多所以设计出来的SQL及其复杂。下面就是初始设计出来的SQL:

SELECT E.*, comp.COMPANY_NAME FROM AU_COMPANY comp, (
    SELECT SUM(points.ORDER_AMOUNT) QUANCUN_PRICE_SUM, COUNT(points.ID) QUANCUN_AMOUNT_SUM, points.SETTLE_COMP_ID COMPANY_ID, substr(points.ORDER_DATE,4,8) ORDER_DATE FROM ECP_CUSTOMER_POINTS_ORDER points inner join (        
        SELECT comp.ID FROM AU_COMPANY comp INNER JOIN (
            SELECT distinct REL.PARTYID from (SELECT distinct C.ID FROM AU_PARTYRELATION REL, AU_PARTYTYPE TYP, AU_COMPANY C WHERE REL.PARTYTYPE_ID =TYP.ID AND TYPE_LEVEL='2' AND TYP.NAME  ='公司' AND C.ID=REL.PARTYID AND C.ISFOODCARD='1') A, AU_PARTYRELATION REL, AU_PARTYTYPE TYP WHERE REL.PARTYTYPE_ID =TYP.ID AND TYP.NAME  ='公司' START WITH REL.PARTYID = A.ID CONNECT BY PRIOR REL.PARTYID =REL.PARENT_PARTYID
        ) B ON comp.SETTLE_UNIT_ID=B.PARTYID AND comp.IS_SETTLEMENT_UNIT ='1'         
    ) D ON points.SETTLE_COMP_ID = D.ID WHERE points.STATUS='3' group by points.SETTLE_COMP_ID, substr(points.ORDER_DATE,4,8)
) E WHERE E.COMPANY_ID=comp.ID 
union SELECT 0 QUANCUN_PRICE_SUM, 0 QUANCUN_AMOUNT_SUM, F.COLUMN2 COMPANY_ID,  substr(sysdate,4,8) ORDER_DATE, F.COMPANY_NAME  COMPANY_NAME FROM (
    SELECT comp3.* FROM AU_COMPANY comp3 INNER JOIN (
        SELECT distinct REL.PARTYID FROM (SELECT distinct C.ID FROM AU_PARTYRELATION REL, AU_PARTYTYPE TYP, AU_COMPANY C WHERE REL.PARTYTYPE_ID =TYP.ID AND TYPE_LEVEL='2' AND TYP.NAME  ='公司' AND C.ID=REL.PARTYID AND C.ISFOODCARD='1') A, AU_PARTYRELATION REL, AU_PARTYTYPE TYP WHERE REL.PARTYTYPE_ID =TYP.ID AND TYP.NAME  ='公司' START WITH REL.PARTYID = A.ID CONNECT BY PRIOR REL.PARTYID =REL.PARENT_PARTYID
    ) F ON comp3.SETTLE_UNIT_ID=F.PARTYID AND comp3.IS_SETTLEMENT_UNIT ='1'
) F WHERE F.ID NOT IN (
    SELECT distinct comp2.SETTLE_UNIT_ID from AU_COMPANY comp2,ECP_CUSTOMER_POINTS_ORDER points3 where comp2.SETTLE_UNIT_ID=points3.SETTLE_COMP_ID and points3.STATUS='3'
)

     仔细再研究一下自己的SQL,可以看出里面有基本上重复的SQL,重复的SQL可以合并到一块,怎么合并呢,用存储过程的话,要先定义存储过程,在使用的时候再call存储过程。要使用临时表的话,要先定义临时表,再insert进去数据。这两者都要DBA的权限,而我们上生产的时候连个select权限都没有。所以最后使用with关键字,使用的时候要注意with放在SQL最前面的话,定义出来的结果集能一直被后面的SQL引用到,写在中间的话由于with不能作为子句,定义也不能被后面的SQL引用到。

     使用Group By的话,只能返回单行,而Oracle 8.1.6之后引入的分析函数over()可以返回多行,并且可以查询多个列,综上设计出来的SQL如下:

WITH temp2 AS(
     SELECT comp.ID, comp.COMPANY_NAME  FROM AU_COMPANY comp INNER JOIN (
         SELECT distinct REL.PARTYID from (SELECT distinct C.ID FROM AU_PARTYRELATION REL, AU_PARTYTYPE TYP, AU_COMPANY C WHERE REL.PARTYTYPE_ID =TYP.ID AND TYPE_LEVEL='2' AND TYP.NAME  ='公司' AND C.ID=REL.PARTYID AND C.ISFOODCARD='1') A, AU_PARTYRELATION REL, AU_PARTYTYPE TYP WHERE REL.PARTYTYPE_ID =TYP.ID AND TYP.NAME  ='公司' START WITH REL.PARTYID = A.ID CONNECT BY PRIOR REL.PARTYID =REL.PARENT_PARTYID
     ) B ON comp.SETTLE_UNIT_ID=B.PARTYID AND comp.IS_SETTLEMENT_UNIT ='1'
)SELECT DISTINCT temp3.QUANCUN_AMOUNT_SUM, substr(points.ORDER_DATE,4,8) ORDER_DATE, points.COM_NAME COMPANY_NAME, points.SETTLE_COMP_ID COMPANY_ID, SUM(points.ORDER_AMOUNT) OVER (PARTITION BY points.SETTLE_COMP_ID) QUANCUN_PRICE_SUM FROM ECP_CUSTOMER_POINTS_ORDER points,temp2,(SELECT COUNT(points2.SETTLE_COMP_ID) QUANCUN_AMOUNT_SUM, points2.SETTLE_COMP_ID FROM ECP_CUSTOMER_POINTS_ORDER points2 WHERE 
     points2.STATUS='3' GROUP BY points2.SETTLE_COMP_ID) temp3 WHERE points.STATUS='3'AND points.SETTLE_COMP_ID IS NOT NULL AND points.SETTLE_COMP_ID=temp2.ID AND temp3.SETTLE_COMP_ID=points.SETTLE_COMP_ID AND  substr(points.ORDER_DATE,4,8)= substr(sysdate,4,8)  
         UNION(SELECT 0 QUANCUN_PRICE_SUM, substr(sysdate,4,8) ORDER_DATE, temp2.COMPANY_NAME COMPANY_NAME, temp2.ID COMPANY_ID,  0 QUANCUN_AMOUNT_SUM FROM temp2 WHERE temp2.ID NOT IN(SELECT distinct comp2.SETTLE_UNIT_ID from AU_COMPANY comp2,ECP_CUSTOMER_POINTS_ORDER points3 where comp2.SETTLE_UNIT_ID=points3.SETTLE_COMP_ID and points3.STATUS='3')
)  ORDER BY QUANCUN_PRICE_SUM

 

转载于:https://my.oschina.net/wliming/blog/701381

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值