2017-04-17 72 views
0

我正在尝试在plsql中编写一个程序,该程序需要两个参数:。该过程为表格生成数据 - loanreport。该过程为贷款类型表中的所有贷款类型生成。当程序运行它应该填充表:在plsql程序中无法找出循环的光标

  1. 封闭贷款金额如果(与状态= 6贷款的贷款金额之和)不贷款具有状态= 6,则关闭贷款数量为0.

    4. 平均关账期间

下面是相关的表:

CREATE TABLE LOANDETAILS 
(LOANNO VARCHAR2(11) primary key, 
    PROPERTYID VARCHAR2(10), 
    CUSTID CHAR(8), 
    LOANTYPE VARCHAR2(20), 
    LOANSTATUSCODE NUMBER(3,0), 
    LOANAMOUNT NUMBER(10,2), 
    RATE NUMBER(5,2), 
    LOANCREATIONDATE DATE, 
    LOANSTATUSDATE DATE, 
    constraint loandet_prop_fk foreign key(PROPERTYID) references PROPERTIES(propertyid), 
    constraint loandet_cust_fk foreign key(CUSTID) references customers(custid), 
    constraint loandet_lt_fk foreign key (LOANTYPE) references loantypes(loantype) 
    ); 
    --insert 
Insert into LOANDETAILS values ('L1000000001','P1000001','C1000001','Conventional',1,87975,9,to_date('26-JUL-2016','DD-MON-YY'),to_date('02-AUG-2016','DD-MON-YYYY')); 
Insert into LOANDETAILS values ('L1000000009','P1000009','C1000009','FHA',6,160055,4.5,to_date('30-NOV-2016','DD-MON-YYYY'),to_date('07-DEC-2016','DD-MON-YYYY')); 
Insert into LOANDETAILS values ('L1000000010','P1000010','C1000010','VA',2,217600,7.5,to_date('30-NOV-2016','DD-MON-YYYY'),to_date('07-DEC-2016','DD-MON-YYYY')); 


CREATE TABLE LOANTYPES 
    (ltID char(5) constraint loantypes_pk primary key, 
    loantype VARCHAR2(20) constraint loantypes_lt_unique UNIQUE, 
    description VARCHAR2(100), 
    active char(1) constraint loantypes_active CHECK (active IN ('Y','N')) -- if loan type is currently being offered 
    ); 
Insert into loantypes values ('LT001', 'VA', 'Service members, veterans or eligible family','Y'); 
Insert into loantypes values ('LT002', 'FHA', 'Federal Housing Administration eligible loans', 'Y'); 
Insert into loantypes values ('LT003', 'Conventional', 'Standard loan','Y'); 
Insert into loantypes values ('LT004', 'Employee', 'Eligible employees of the organization','Y'); 
Insert into loantypes values ('LT005', 'Reconstruct', 'Relief work reconstruction','N'); 

CREATE TABLE LOANTYPEREPORT 
    (LOANTYPE VARCHAR2(20), 
    MONTH number(2,0), 
    YEAR NUMBER(4,0), 
    CLOSEDLOANSAMOUNT NUMBER(15,2), 
    AVERAGECLOSINGPERIOD NUMBER(5,2), 
    constraint loantr_pk PRIMARY KEY (LOANTYPE, RMONTH, RYEAR) 
    ); 

我是新来的SQL和我清楚有一些知识方面的差距。我正在尝试创建一个过程,然后想要创建一个游标并用for循环遍历游标以创建所需的报告。这是我的不完整的代码:

CREATE OR REPLACE PROCEDURE loan_type_report_procedure (Month loantypereport.month%type, Year loantypereport.year%type) AS 

CURSOR C1 IS 
SELECT l.loantype, 
     loanamount, 
     loancreationdate, 
     loanstatusdate, 
     loanstatuscode, 
     to_char(LOANCREATIONDATE, 'mm') AS rMonth, 
     to_char(LOANCREATIONDATE, 'YYYY') AS rYEAR 
FROM LOANTYPES l 
JOIN LOANDETAILS d 
ON l.loantype = d.loantype 
WHERE Month = to_char(LOANCREATIONDATE, 'mm') 
     AND Year = to_char(LOANCREATIONDATE, 'YYYY') 

BEGIN 
FOR loan_rec in C1 LOOP 

据我了解循环逐行在游标中。如果我想要一个包含loantype,月份,年份,已结束贷款金额和平均关闭期的最终表贷款类型报告 - 我如何完成这项工作?贷款类型分组合并了贷款总额和平均期末数。我会在光标选择语句中使用一个组吗?

感谢您的洞察力

+0

你可以写一些东西,如以下:INSERT INTO table_name的 SELECT l.loantype, SUM(CASE WHEN loanstatuscode = 6 THEN loanamount ELSE 0 END)loanamount, loancreationdate, loanstatusdate, loanstatuscode, TO_CHAR(LOANCREATIONDATE, '毫米')AS rMonth, TO_CHAR(LOANCREATIONDATE, 'YYYY')AS rYEAR FROM LOANTYPES升 JOINðLOANDETAILS ON l.loantype = d。loantype WHERE Month = to_char(LOANCREATIONDATE,'mm') AND Year = to_char(LOANCREATIONDATE,'YYYY') –

+0

Mike我并不完全确定自己理解了所有持续时间的标准,但包含了一些示例。如果没有贷款在一个月内关闭,我离开了平均值'NULL'。这是你在平均持续时间内想到的吗? – alexgibbs

回答

0

如果我正确理解你的问题,你想通过自己的LOANTYPE总结贷款的数量,每月,和被关闭的贷款(LOANSTATUSCODE = 6),你他们喜欢SUM他们的金额和记录他们的贷款时间跨度AVERAGE
LOANTYPEREPORT的外观看来,您似乎打算将此平均跨度设为几天。

要做到这一点,您不需要使用PL/SQL。这可以通过传统SQL完成。我只是猜测决定贷款持续时间的标准是什么,所以我将在下面简要介绍一些例子。

在这个例子中,我需要稍微修改你的表格,因为它们引用了你的文章中没有包括的其他表格(我删除了LOANDET_PROP_FKLOANDET_CUST_FK)。

创建示例表后,创建LOANTYPEREPORT表(从你的榜样编译略有修改):

CREATE TABLE LOANTYPEREPORT 
(LOANTYPE VARCHAR2(20), 
MONTH NUMBER(2,0), 
YEAR NUMBER(4,0), 
CLOSEDLOANSAMOUNT NUMBER(15,2), 
AVERAGECLOSINGPERIOD NUMBER(5,2), 
    CONSTRAINT LOANTR_PK PRIMARY KEY (LOANTYPE, MONTH, YEAR) 
); 

另外,我加了一些额外的数据,一些FHA和常规贷款,以帮助区分SUM s和持续时间在下面的例子中。

Insert into LOANDETAILS values ('L1000000001','P1000001','C1000001','Conventional',1,87975,9,to_date('26-JUL-2016','DD-MON-YY'),to_date('02-AUG-2016','DD-MON-YYYY')); 
Insert into LOANDETAILS values ('L1000000009','P1000009','C1000009','FHA',6,160055,4.5,to_date('30-NOV-2016','DD-MON-YYYY'),to_date('07-DEC-2016','DD-MON-YYYY')); 
Insert into LOANDETAILS values ('L1000000010','P1000010','C1000010','VA',2,217600,7.5,to_date('30-NOV-2016','DD-MON-YYYY'),to_date('07-DEC-2016','DD-MON-YYYY')); 
Insert into LOANDETAILS values ('L1000000011','P1000010','C1000010','VA',6,217600,7.5,to_date('30-NOV-2016','DD-MON-YYYY'),to_date('07-DEC-2016','DD-MON-YYYY')); 
Insert into LOANDETAILS values ('L1000000012','P1000010','C1000010','VA',6,111111,7.5,to_date('30-NOV-2016','DD-MON-YYYY'),to_date('17-DEC-2016','DD-MON-YYYY')); 
Insert into LOANDETAILS values ('L1000000013','P1000010','C1000010','VA',2,222222,7.5,to_date('30-NOV-2016','DD-MON-YYYY'),to_date('27-DEC-2016','DD-MON-YYYY')); 
Insert into LOANDETAILS values ('L1000000014','P1000010','C1000010','Conventional',6,333333,7.5,to_date('30-NOV-2016','DD-MON-YYYY'),to_date('27-JAN-2017','DD-MON-YYYY')); 
Insert into LOANDETAILS values ('L1000000015','P1000010','C1000010','Conventional',5,333333,7.5,to_date('30-NOV-2016','DD-MON-YYYY'),to_date('27-FEB-2017','DD-MON-YYYY')); 
Insert into LOANDETAILS values ('L1000000016','P1000010','C1000010','Conventional',4,333333,7.5,to_date('30-NOV-2016','DD-MON-YYYY'),to_date('27-MAR-2017','DD-MON-YYYY')); 
Insert into LOANDETAILS values ('L1000000017','P1000010','C1000010','FHA',4,444444,7.5,to_date('30-NOV-2016','DD-MON-YYYY'),to_date('27-APR-2017','DD-MON-YYYY')); 
Insert into LOANDETAILS values ('L1000000018','P1000010','C1000010','FHA',6,200000,7.5,to_date('30-NOV-2016','DD-MON-YYYY'),to_date('27-APR-2017','DD-MON-YYYY')); 
Insert into LOANDETAILS values ('L1000000019','P1000010','C1000010','FHA',6,300000,7.5,to_date('30-NOV-2016','DD-MON-YYYY'),to_date('27-MAY-2017','DD-MON-YYYY')); 
Insert into LOANDETAILS values ('L1000000020','P1000010','C1000010','FHA',6,300000,7.5,to_date('30-NOV-2016','DD-MON-YYYY'),to_date('22-MAY-2017','DD-MON-YYYY')); 

然后,您可以加载报表。
示例1这假定贷款期限平均只包括已结清的贷款,贷款期限在LOANCREATIONDATELOANSTATUSDATE之间,而且您只需要数月的数据和贷款实际上已关闭的贷款类型。这意味着2016年7月将不会被包括在内,因为当月没有关闭贷款。

INSERT INTO LOANTYPEREPORT 
    SELECT 
    LOANDETAILS.LOANTYPE, 
    EXTRACT(MONTH FROM LOANDETAILS.LOANSTATUSDATE) AS MONTH, 
    EXTRACT(YEAR FROM LOANDETAILS.LOANSTATUSDATE) AS YEAR, 
    SUM(LOANDETAILS.LOANAMOUNT) AS CLOSED_LOAN_AMOUNT, 
    AVG(LOANDETAILS.LOANSTATUSDATE - LOANDETAILS.LOANCREATIONDATE) AS AVERAGE_LOAN_DURATION 
    FROM LOANDETAILS 
    WHERE LOANDETAILS.LOANSTATUSCODE = 6 
    GROUP BY 
    LOANDETAILS.LOANTYPE, 
    EXTRACT(YEAR FROM LOANDETAILS.LOANSTATUSDATE), 
    EXTRACT(MONTH FROM LOANDETAILS.LOANSTATUSDATE); 

然后看看它的所作所为:

SELECT YEAR,MONTH,LOANTYPE,CLOSEDLOANSAMOUNT,AVERAGECLOSINGPERIOD 
FROM LOANTYPEREPORT 
ORDER BY YEAR, MONTH, LOANTYPE; 


YEAR MONTH LOANTYPE  CLOSEDLOANSAMOUNT AVERAGECLOSINGPERIOD 
2016 12  FHA   160055    7      
2016 12  VA   328711    12      
2017 1  Conventional 333333    58      
2017 4  FHA   200000    148     
2017 5  FHA   600000    175.5     

例2:但是,如果你要包括数据在没有贷款被关闭给定的贷款型个月(我不是当然,但这可能是您的文章中的第三项),那么您需要列举几个月。
你可以这样做几种方式,但我就包括在本例中额外的查询,设置界限为2016年 - 2018年

运行插件:

INSERT INTO LOANTYPEREPORT 
    WITH YEAR_MONTH AS(
    SELECT THE_MONTH.MONTH_NUMBER, 
     THE_YEAR.YEAR_NUMBER 
    FROM 
     (SELECT LEVEL AS MONTH_NUMBER FROM DUAL CONNECT BY LEVEL < 13) THE_MONTH 
     CROSS JOIN 
     (SELECT YEAR_NUMBER FROM 
     (SELECT LEVEL AS YEAR_NUMBER FROM DUAL CONNECT BY LEVEL < 2019) 
     WHERE YEAR_NUMBER BETWEEN 2016 AND 2018) THE_YEAR 
) 
    SELECT 
    LOANTYPES.LOANTYPE, 
    YEAR_MONTH.MONTH_NUMBER, 
    YEAR_MONTH.YEAR_NUMBER, 
    SUM(COALESCE(CLOSED_LOAN.LOANAMOUNT,0)) AS CLOSED_LOAN_AMOUNT, 
    AVG(CLOSED_LOAN.LOAN_DURATION) AS AVERAGE_LOAN_DURATION 
    FROM 
    YEAR_MONTH 
    CROSS JOIN LOANTYPES 
     LEFT OUTER JOIN (SELECT EXTRACT(MONTH FROM LOANDETAILS.LOANSTATUSDATE) AS MONTH, 
           EXTRACT(YEAR FROM LOANDETAILS.LOANSTATUSDATE) AS YEAR, 
         LOANDETAILS.LOANTYPE, 
         LOANDETAILS.LOANAMOUNT, 
         LOANDETAILS.LOANSTATUSDATE - LOANDETAILS.LOANCREATIONDATE AS LOAN_DURATION 
         FROM LOANDETAILS 
    WHERE LOANDETAILS.LOANSTATUSCODE = 6) CLOSED_LOAN 
    ON YEAR_MONTH.YEAR_NUMBER = CLOSED_LOAN.YEAR 
AND YEAR_MONTH.MONTH_NUMBER = CLOSED_LOAN.MONTH 
    AND LOANTYPES.LOANTYPE = CLOSED_LOAN.LOANTYPE 
    GROUP BY YEAR_NUMBER, MONTH_NUMBER, LOANTYPES.LOANTYPE 
ORDER BY YEAR_NUMBER, MONTH_NUMBER, LOANTYPES.LOANTYPE; 

,看看数据产生:

YEAR MONTH LOANTYPE  CLOSEDLOANSAMOUNT AVERAGECLOSINGPERIOD 
2016 1  Conventional 0           
2016 1  Employee  0           
2016 1  FHA   0           
2016 1  Reconstruct 0           
2016 1  VA   0           
2016 2  Conventional 0           
... 
... 
... 
2016 12  Conventional 0           
2016 12  Employee  0           
2016 12  FHA   160055    7      
2016 12  Reconstruct 0           
2016 12  VA   328711    12      
2017 1  Conventional 333333    58      
2017 1  Employee  0           
2017 1  FHA   0      
2017 4  FHA   200000    148     
2017 4  Reconstruct 0           
2017 4  VA   0         
2017 5  Conventional 0           
2017 5  Employee  0           
2017 5  FHA   600000    175.5     
2017 5  Reconstruct 0           
2017 5  VA   0           
2017 6  Conventional 0           
2017 6  Employee  0           
2017 6  FHA   0        

这样你得到的关闭量贷款和封闭每月每一种类型的,或零,如果没有被关闭。

编辑一个从函数返回的例子。

只是为了重申一下,您不需要使用函数来做这种报告。
但是,如果你有一个要求,使用功能,这里有一个例子:

首先,创建您的返回类型:

CREATE TYPE LOAN_TYPE_MONTH_REPORT IS OBJECT (
    LOANTYPE VARCHAR2(20), 
    MONTH number(2,0), 
    YEAR NUMBER(4,0), 
    CLOSEDLOANSAMOUNT NUMBER(15,2), 
    AVERAGECLOSINGPERIOD NUMBER(5,2) 
); 
/

CREATE TYPE LOAN_TYPE_MONTH_REPORT_LIST IS TABLE OF LOAN_TYPE_MONTH_REPORT; 
/

然后创建你的函数:

CREATE FUNCTION GET_LOAN_TYPE_REPORT_FOR_MONTH(P_YEAR IN NUMBER, P_MONTH IN NUMBER) 
    RETURN LOAN_TYPE_MONTH_REPORT_LIST 
    IS 
    V_MONTH_REPORT LOAN_TYPE_MONTH_REPORT_LIST; 
    BEGIN 
    SELECT 
     LOAN_TYPE_MONTH_REPORT(
     THE_MONTH_YEAR.LOANTYPE, 
     THE_MONTH_YEAR.THE_MONTH, 
     THE_MONTH_YEAR.THE_YEAR, 
     COALESCE(CLOSED_LOAN_SUMMARY.CLOSED_LOAN_AMOUNT,0), 
     CLOSED_LOAN_SUMMARY.AVERAGE_LOAN_DURATION) 
    BULK COLLECT INTO V_MONTH_REPORT 
    FROM 
     (SELECT P_YEAR AS THE_YEAR, P_MONTH AS THE_MONTH, LOANTYPES.LOANTYPE FROM LOANTYPES) THE_MONTH_YEAR 
     LEFT OUTER JOIN 
     (SELECT 
     LOANDETAILS.LOANTYPE, 
     EXTRACT(MONTH FROM LOANDETAILS.LOANSTATUSDATE) AS THE_MONTH, 
     EXTRACT(YEAR FROM LOANDETAILS.LOANSTATUSDATE) AS THE_YEAR, 
     SUM(LOANDETAILS.LOANAMOUNT) AS CLOSED_LOAN_AMOUNT, 
     AVG(LOANDETAILS.LOANSTATUSDATE - LOANDETAILS.LOANCREATIONDATE) AS AVERAGE_LOAN_DURATION 
     FROM LOANDETAILS 
     WHERE LOANDETAILS.LOANSTATUSCODE = 6 
     GROUP BY 
     LOANDETAILS.LOANTYPE, 
     EXTRACT(YEAR FROM LOANDETAILS.LOANSTATUSDATE), 
     EXTRACT(MONTH FROM LOANDETAILS.LOANSTATUSDATE)) CLOSED_LOAN_SUMMARY 
     ON THE_MONTH_YEAR.THE_YEAR = CLOSED_LOAN_SUMMARY.THE_YEAR 
      AND THE_MONTH_YEAR.THE_MONTH = CLOSED_LOAN_SUMMARY.THE_MONTH 
      AND THE_MONTH_YEAR.LOANTYPE = CLOSED_LOAN_SUMMARY.LOANTYPE; 
    RETURN V_MONTH_REPORT; 
    END; 
/

然后测试它: 这里是一个月与两个贷款类型与关闭:

SELECT * FROM TABLE(GET_LOAN_TYPE_REPORT_FOR_MONTH(2016,12)); 
LOANTYPE  MONTH YEAR CLOSEDLOANSAMOUNT AVERAGECLOSINGPERIOD 
Employee  12  2016 0           
VA   12  2016 328711    12      
Reconstruct 12  2016 0           
FHA   12  2016 160055    7      
Conventional 12  2016 0          

或者只用一个贷款类型有关闭一个月:

SELECT * FROM TABLE(GET_LOAN_TYPE_REPORT_FOR_MONTH(2017,01)); 
LOANTYPE  MONTH YEAR CLOSEDLOANSAMOUNT AVERAGECLOSINGPERIOD 
Employee  1  2017 0           
Reconstruct 1  2017 0           
FHA   1  2017 0           
VA   1  2017 0           
Conventional 1  2017 333333    58      
+0

嗨亚历克斯,比你再详细的答案。我很感激你的时间,并且可以保证它帮助我将自己的思想包装在SQL中。如果我想把它变成一个具有月份和年份输入的程序,那么你对这个报告有什么看法? – Mike

+0

谢谢@Mike当然,我可以看看。有关目标和遇到的任何问题的更多细节将有所帮助。你能告诉我,你想要什么程序来处理输入?您是否正在寻找仅在该月份或上至该月份的所有历史记录中加载报告数据的过程?是否需要单个过程加载表并返回数据,或者加载和查询是否是两个单独的过程?谢谢 – alexgibbs

+0

嗨@Alex,这将是一个月和年作为输入的过程。它仅返回仅在该月份和年份的报告。返回的表格将包含月份,年份,已关闭的贷款金额和平均关闭期间。已关闭的贷款金额和平均关闭期只与状态= 6的贷款有关。如果没有状态= 6的贷款,则关闭的贷款金额和平均关闭期应为0.我在上面的解决方案中遇到的问题是我不知道如何循环游标,然后通过贷款类型汇总数据 – Mike