重写 运行 总计 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
的东西。
我想重写以下 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
的东西。