我想重写以下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。 感谢
答案 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
之类的内容。