重写运行的总sql查询

时间:2015-01-23 00:22:08

标签: sql oracle rewrite

我想重写以下SQL以使其更有效(可能使用Oracle分析函数,但任何有效的重写都可以)。 SQL目前有效,运行只需要一段时间: -

创建表:

CREATE TABLE ITEM_REF 
(
  DEPT_ID VARCHAR2(5 BYTE) NOT NULL 
, ID VARCHAR2(11 BYTE) NOT NULL 
, ID_TYPE VARCHAR2(1 BYTE) NOT NULL 
, ITEM_CHARGE VARCHAR2(15 BYTE) NOT NULL 
, ITEM_PAYMENT VARCHAR2(15 BYTE) NOT NULL 
, ITEM_DATE DATE NOT NULL 
, REF_AMT NUMBER(14, 2) NOT NULL
)

插入表格:

INSERT INTO ITEM_REF VALUES ('POLLD', '0004', 'O', '000000000000001', '000000000000002', '11/JUN/09', '1550')
INSERT INTO ITEM_REF VALUES ('POLLD', '0004', 'O', '000000000000003', '000000000000004', '23/OCT/09', '3100')
INSERT INTO ITEM_REF VALUES ('POLLD', '0004', 'O', '000000000000005', '000000000000007', '02/AUG/10', '3500')
INSERT INTO ITEM_REF VALUES ('POLLD', '0004', 'O', '000000000000008', '000000000000010', '15/DEC/10', '3500')
INSERT INTO ITEM_REF VALUES ('POLLD', '0004', 'O', '000000000000003', '000000000000004', '14/APR/11', '0')
INSERT INTO ITEM_REF VALUES ('POLLD', '0004', 'O', '000000000000012', '000000000000014', '14/APR/11', '3100')
INSERT INTO ITEM_REF VALUES ('POLLD', '0004', 'O', '000000000000021', '000000000000022', '13/JUL/11', '3500')
INSERT INTO ITEM_REF VALUES ('POLLD', '0004', 'O', '000000000000016', '000000000000018', '03/JUN/11', '1550')
INSERT INTO ITEM_REF VALUES ('POLLD', '0004', 'O', '000000000000016', '000000000000018', '22/JUN/11', '0')
INSERT INTO ITEM_REF VALUES ('POLLD', '0004', 'O', '000000000000017', '000000000000019', '22/JUN/11', '1550')
INSERT INTO ITEM_REF VALUES ('POLLD', '0004', 'O', '000000000000005', '000000000000007', '13/JUL/11', '0')
INSERT INTO ITEM_REF VALUES ('POLLD', '0004', 'O', '000000000000021', '000000000000022', '19/SEP/11', '0')
INSERT INTO ITEM_REF VALUES ('POLLD', '0004', 'O', '000000000000021', '000000000000024', '19/SEP/11', '3500')
INSERT INTO ITEM_REF VALUES ('POLLD', '0004', 'O', '000000000000023', '000000000000025', '21/NOV/11', '1550')
INSERT INTO ITEM_REF VALUES ('POLLD', '0004', 'O', '000000000000027', '000000000000030', '03/NOV/14', '384')
INSERT INTO ITEM_REF VALUES ('POLLD', '0004', 'O', '000000000000028', '000000000000030', '03/NOV/14', '247.8')
INSERT INTO ITEM_REF VALUES ('POLLD', '0004', 'O', '000000000000026', '000000000000029', '27/OCT/14', '2465')
INSERT INTO ITEM_REF VALUES ('POLLD', '0002', 'O', '000000000000001', '000000000000004', '07/JUL/10', '88.4')
INSERT INTO ITEM_REF VALUES ('POLLD', '0002', 'O', '000000000000001', '000000000000004', '13/JUL/10', '88.4')
INSERT INTO ITEM_REF VALUES ('POLLD', '0002', 'O', '000000000000001', '000000000000006', '17/AUG/10', '353.6')
INSERT INTO ITEM_REF VALUES ('POLLD', '0002', 'O', '000000000000001', '000000000000004', '21/AUG/10', '88.4')
INSERT INTO ITEM_REF VALUES ('POLLD', '0002', 'O', '000000000000001', '000000000000006', '21/AUG/10', '87.6')
INSERT INTO ITEM_REF VALUES ('POLLD', '0002', 'O', '000000000000001', '000000000000006', '25/AUG/10', '353.6')

当前正在运行的总SQL:

SELECT A.DEPT_ID, A.ID, A.ID_TYPE, A.ITEM_CHARGE, A.ITEM_DATE
, NVL((SELECT SUM(B.REF_AMT) FROM ITEM_REF B
        WHERE B.DEPT_ID     = A.DEPT_ID
          AND B.ID          = A.ID
          AND B.ID_TYPE     = A.ID_TYPE
          AND B.ITEM_CHARGE = A.ITEM_CHARGE
          AND B.ITEM_DATE   =
            (SELECT MAX(B2.ITEM_DATE)
                FROM ITEM_REF B2
                WHERE B2.DEPT_ID      = B.DEPT_ID
                  AND B2.ID           = B.ID
                  AND B2.ID_TYPE      = B.ID_TYPE
                  AND B2.ITEM_CHARGE  = B.ITEM_CHARGE
                  AND B2.ITEM_PAYMENT = B.ITEM_PAYMENT
                  AND B2.ITEM_DATE   <= A.ITEM_DATE)
        ), 0)
FROM ITEM_REF A GROUP BY A.DEPT_ID, A.ID, A.ID_TYPE, A.ITEM_CHARGE, A.ITEM_DATE

我试图使用Oracle分析函数,如下所示: -

SELECT A.DEPT_ID
, A.ID
, A.ID_TYPE
, A.ITEM_CHARGE
, A.ITEM_DATE
, (SELECT SUM(B.REF_AMT)
    FROM ITEM_REF B
    WHERE B.DEPT_ID   =A.DEPT_ID
    AND B.ID          =A.ID
    AND B.ID_TYPE     =A.ID_TYPE
    AND B.ITEM_CHARGE =A.ITEM_CHARGE
    AND B.ITEM_DATE   =
        (SELECT  C.ITEM_DATE
        FROM
            (SELECT  D.ITEM_DATE
                    , ROW_NUMBER() OVER (PARTITION BY D.DEPT_ID, D.ID, D.ID_TYPE, D.ITEM_CHARGE, D.ITEM_PAYMENT ORDER BY D.ITEM_DATE DESC) RN
                FROM ITEM_REF D
                WHERE D.ITEM_DATE <= A.ITEM_DATE
                ) C
        WHERE C.RN =1
        )
    )
FROM ITEM_REF A

对A.ITEM_DATE的引用会破坏此代码,因为内部SQL无法引用表ITEM_REF A.我的方法是使用Oracle分析函数从主SQL表(即ITEM_REF A)返回给定日期的最大ITEM_DATE。 感谢

1 个答案:

答案 0 :(得分:0)

更新回答

在开始时使用数据分组进行查询,并使用row_number对行进行排序。我认为如果分组后你的行数少得多,可能会更好。尝试反对750,000行,新版本更快。 但我更喜欢你的查询,它更具可读性; - )

with ds as (select dept_id, id, id_type, item_charge, item_date, item_payment, sum(ref_amt) ref_amt
  from item_ref
  group by dept_id, id, id_type, item_charge, item_date, item_payment),
dsp as (
  select ds1.dept_id, ds1.id, ds1.id_type, ds1.item_charge, ds1.item_date, ds2.ref_amt,
      row_number() over (partition by ds2.dept_id, ds2.id, ds2.id_type, ds2.item_charge, 
        ds2.item_payment, ds1.item_date order by ds2.item_date desc) rn 
    from ds ds1 join ds ds2 on ds2.dept_id=ds1.dept_id and ds2.id=ds1.id and ds2.id_type=ds1.id_type 
        and ds2.item_charge=ds1.item_charge and ds2.item_date<=ds1.item_date)
select dept_id, id, id_type, item_charge, item_date, sum(ref_amt) 
  from dsp where rn=1
  group by dept_id, id, id_type, item_charge, item_date

以下是先前的答案,现在不是实际的:

也许我错了,但是你当前运行的查询最终返回简单的总和,就像在列amt中一样。 我检查结果三次添加样本记录,我认为没有区别。

select dept_id, id, id_type, item_charge, item_date, 
    sum(ref_amt) amt, 
    sum(sum(ref_amt)) over (partition by dept_id, id, id_type, item_charge 
      order by item_date) amt_aggr
  from item_ref a
  group by dept_id, id, id_type, item_charge, item_date

如果您想获得总和增加,您可以使用amt_aggr之类的内容。