我一直想知道如何在Oracle中改进此查询:
SELECT FN_FORMAT_PEROPE(PEROPE) AS PERIODO,
NVL((SELECT COUNT(1) FROM PG_PAGO P INNER JOIN PG_DETALLE_PAGO DP ON P.IDPAGO = DP.IDPAGO WHERE DP.ESTADO = 1 AND P.PEROPE = R.PEROPE),0) AS NRO_EMITIDOS,
NVL((SELECT SUM(DP.MONTO) FROM PG_PAGO P INNER JOIN PG_DETALLE_PAGO DP ON P.IDPAGO = DP.IDPAGO WHERE DP.ESTADO = 1 AND P.PEROPE = R.PEROPE),0) AS MONTO_EMITIDO,
NVL((SELECT COUNT(1) FROM PG_PAGO P INNER JOIN PG_DETALLE_PAGO DP ON P.IDPAGO = DP.IDPAGO WHERE DP.ESTADO = 2 AND P.PEROPE = R.PEROPE),0) AS NRO_ABONADOS,
NVL((SELECT SUM(DP.MONTO) FROM PG_PAGO P INNER JOIN PG_DETALLE_PAGO DP ON P.IDPAGO = DP.IDPAGO WHERE DP.ESTADO = 2 AND P.PEROPE = R.PEROPE),0) AS MONTO_ABONADO,
NVL((SELECT COUNT(1) FROM PG_PAGO P INNER JOIN PG_DETALLE_PAGO DP ON P.IDPAGO = DP.IDPAGO WHERE DP.ESTADO = 3 AND P.PEROPE = R.PEROPE),0) AS NRO_RECHAZADOS,
NVL((SELECT SUM(DP.MONTO) FROM PG_PAGO P INNER JOIN PG_DETALLE_PAGO DP ON P.IDPAGO = DP.IDPAGO WHERE DP.ESTADO = 3 AND P.PEROPE = R.PEROPE),0) AS MONTO_RECHAZADO,
NVL((SELECT COUNT(1) FROM PG_PAGO P INNER JOIN PG_DETALLE_PAGO DP ON P.IDPAGO = DP.IDPAGO WHERE DP.ESTADO = 4 AND P.PEROPE = R.PEROPE),0) AS NRO_INDEBIDOS,
NVL((SELECT SUM(DP.MONTO) FROM PG_PAGO P INNER JOIN PG_DETALLE_PAGO DP ON P.IDPAGO = DP.IDPAGO WHERE DP.ESTADO = 4 AND P.PEROPE = R.PEROPE),0) AS MONTO_INDEBIDO,
NVL((SELECT COUNT(1) FROM PG_PAGO P /*INNER JOIN PG_DETALLE_PAGO DP ON P.IDPAGO = DP.IDPAGO WHERE DP.ESTADO = 5*/ WHERE P.ESTADO = 5 AND P.PEROPE = R.PEROPE),0) AS NRO_RECUPEROS,
NVL((SELECT SUM(DP.MONTO) FROM PG_PAGO P INNER JOIN PG_DETALLE_PAGO DP ON P.IDPAGO = DP.IDPAGO WHERE DP.ESTADO = 5 AND P.PEROPE = R.PEROPE),0) AS MONTO_RECUPERO
FROM PG_RESOLUCIONES R ORDER BY R.PEROPE ASC;
考虑一下:
感谢您的帮助。
答案 0 :(得分:3)
假设您的查询中的内部联接的注释是一个测试假象,您可以使用沿着这条线的旋转查询一次性从* _pago表中获取结果:
SELECT *
FROM (SELECT p.perope,
dp.estado,
dp.monto
FROM pg_pago p
INNER JOIN pg_detalle_pago dp ON p.idpago = dp.idpago
WHERE dp.estado IN (1, 2, 3, 4, 5))
PIVOT (COUNT(*) AS nro,
SUM(dp.monto) AS monto
FOR estado IN (1 AS emitidos,
2 AS abonados,
3 AS rechazados,
4 AS indebidos,
5 AS recuperos));
N.B。未经测试。此外,这适用于Oracle 11g及更高版本。
获得这组结果后,应该很容易将其加入到pg_resoluciones表中,并根据需要对列进行别名。
答案 1 :(得分:2)
解决数据库性能的关键是一次查询表而不是十次。以下是实现此目的的一种方法(警告:未经测试,可能包含错误)
select fn_format_perope(r.perope) as periodo
, sum ( case when dp.estado = 1 and then 1 else 0 end ) as nro_emitidos
, sum ( case when dp.estado = 1 and then dp.monto else 0 end ) as monto_emitido
, sum ( case when dp.estado = 2 and then 1 else 0 end ) as nro_abonados
, sum ( case when dp.estado = 2 and then dp.monto else 0 end ) as monto_abonado
, sum ( case when dp.estado = 3 and then 1 else 0 end ) as nro_rechazados
, sum ( case when dp.estado = 3 and then dp.monto else 0 end ) as monto_rechazado
, sum ( case when dp.estado = 4 and then 1 else 0 end ) as nro_indebidos
, sum ( case when dp.estado = 4 and then dp.monto else 0 end ) as monto_indebido
, sum ( case when dp.estado = 5 and then 1 else 0 end ) as nro_recupero
, sum ( case when dp.estado = 5 and then dp.monto else 0 end ) as monto_recupero
from pg_resoluciones r
left outer join pg_pago p
on p.perope = r.perope
left outer join pg_detalle_pago dp
on p.idpago = dp.idpago
order by r.perope asc;
您需要为PG_PAGO和PG_DETALLE_PAGO使用外连接,因为它们似乎没有匹配的记录(在标量查询中使用NVL()
推断)。
此版本适用于任何版本的Oracle。 @Boneist编写的PIVOT版本更优雅,如果您使用11g或更高版本,这可能是您应该采用的应用程序。