Oracle开放和结束余额 - 需要SQL还是PL / SQL?

时间:2012-09-19 14:52:28

标签: sql oracle

 select year, 
        month ,
        d.PROD_ID, 
        T.CUSTOMER_ID,
        SUM(CASE WHEN D.OP_TYPE = 1 THEN d.qty END)    EARNED,
        SUM(CASE WHEN D.OP_TYPE = 2 THEN d.qty END)    SPEND
FROM TXN_HEADER T  , 
     TXN_DETAIL d , 
     CUSTOMER A,
     PRODUCT e 
WHERE T.AMOUNT > 0 
AND   A.TYPE  =  0
AND   T.CUSTOMER_ID = A.CUSTOMER_ID
AND   T.TXN_PK = D.TXN_PK 
and   d.PROD_ID = e.PROD_ID
and   e.unit = 0
group by year, month ,d.PROD_ID, T.CUSTOMER_ID
ORDER BY 1,2,3,4 

输出如下(此处打开和关闭不是由查询生成的,但我要求必须来自查询)

YEAR MONTH PROD CUSTOMER OPENING EARNED SPEND CLOSING 
---- ----- ---- -------- ------- ------ ----- -------
2012     8  548    12033       0      8     2       6
2012     9  509    12033       0     24     0      24
2012     9  509    12047       0     14     0      14
2012     9  548    12033       6      1     0       7
2012     9  548    12047       0      1     0       1

我需要像上面那样生成输出。这里PROD_ID,CUSTOMER_ID动态地将上一个期末余额作为开头填充,并且它应该按月计算期末余额(开仓+赚取的支出),明智地计算产品。是可以用SQL编写还是需要去PL / SQL?

2 个答案:

答案 0 :(得分:1)

我在分区子句中使用分析,PROD_ID和CUSTOMER_ID,以避免混淆产品和客户。

WITH
MONTHLY_BALANCE AS
(
  SELECT
    YEAR,
    MONTH,
    D.PROD_ID,
    T.CUSTOMER_ID,
    SUM(CASE WHEN D.OP_TYPE = 1 THEN D.QTY ELSE NULL END) EARNED,
    SUM(CASE WHEN D.OP_TYPE = 2 THEN D.QTY ELSE NULL END) SPEND,
  FROM TXN_HEADER T
  JOIN CUSTOMER A 
  ON    T.CUSTOMER_ID = A.CUSTOMER_ID
  JOIN TXN_DETAIL D
  ON    T.TXN_PK = D.TXN_PK
  JOIN PRODUCT E
  ON    D.PROD_ID = E.PROD_ID
  WHERE T.AMOUNT > 0
  AND   A.TYPE = 0
  AND   E.UNIT = 0
  GROUP BY YEAR, MONTH, D.PROD_ID, T.CUSTOMER_ID
)
SELECT
  YEAR,
  MONTH,
  PROD_ID,
  CUSTOMER_ID,
  SUM(NVL(EARNED, 0) - NVL(SPEND, 0)) OVER(PARTITION BY PROD_ID, CUSTOMER_ID ORDER BY YEAR, MONTH ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) OPENING,
  EARNED,
  SPEND,
  SUM(NVL(EARNED, 0) - NVL(SPEND, 0)) OVER(PARTITION BY PROD_ID, CUSTOMER_ID ORDER BY YEAR, MONTH ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT_ROW) CLOSING
FROM MONTHLY_BALANCE
ORDER BY 1, 2, 3, 4

答案 1 :(得分:0)

您的CASE需要ELSE

CASE WHEN D.OP_TYPE = 1 THEN d.qty ELSE 0 END

如果没有其他内容,CASE将在NULL不等于D.OP_TYPE时返回1,而任何内容+ NULL = NULL。当您的WHEN不满意时,它会返回NULL,这就是您没有看到这些列的任何内容的原因。

要计算开始和结算,因为您可能希望LEAD使用LAGSelect year,month,prod_id,customer_id, LAG(closing,1,0) OVER (order by year,month,prod_id,customer_id) as opening, earned,spend ,(LAG(closing,1,0) OVER (order by year,month,prod_id,customer_id)+closing) as closing from (WITH temp AS (select year, month , d.PROD_ID, T.CUSTOMER_ID, 0 OPEN, SUM(CASE WHEN D.OP_TYPE = 1 THEN d.qty END) EARNED, SUM(CASE WHEN D.OP_TYPE = 2 THEN d.qty END) SPEND, 0 CLOSE FROM TXN_HEADER T , TXN_DETAIL d , CUSTOMER A, PRODUCT e WHERE T.AMOUNT > 0 AND A.TYPE = 0 AND T.CUSTOMER_ID = A.CUSTOMER_ID AND T.TXN_PK = D.TXN_PK and d.PROD_ID = e.PROD_ID and e.unit = 0 group by year, month ,d.PROD_ID, T.CUSTOMER_ID ORDER BY 1,2,3,4) SELECT year,month,prod_id,customer_id,open,earned,spend,(open+earned-spend) as closing from temp);

{{1}}