重写 运行 总计 sql 查询

Rewrite running total sql query

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

创建Table:

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
)

插入 Table:

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不能引用table ITEM_REF A.我这里的方法是使用Oracle解析函数来return 从主要 SQL table 到给定日期的最大值 ITEM_DATE 即 ITEM_REF A. 谢谢

更新答案

在开始时使用数据分组查询并使用 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

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

也许我错了,但您当前 运行 查询最终 returns 简单求和,如 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的东西。