【PL/SQL 练习题6】 银行日常业务

看完这章你会学习到以下内容:

  1. 解题的思路
  2. 解题的方法

【PL/SQL 练习题6】 银行日常业务_第1张图片

解题思路:
1.YTD 数据按照产品名分类聚合求和(Group by + Sum函数)
2.产品名称出自TblProduct表,月份出自TblPayments,两表关联。
3.关联后用With...AS 子查询套入查询
4.列数比行数多,通常都是行列转换的结果

创建两张表格
1.tblpayment表格创建语句

--- tblpayment 创建语句:
CREATE TABLE TBLPAYMENTS
   (SID VARCHAR2(10), 
  PAYMENTTIME DATE, 
  PRODUCTID VARCHAR2(10), 
  AMOUNT NUMBER(10,0), 
  PAYMENTSTATUS VARCHAR2(10), 
  SALES VARCHAR2(10), 
  REGION VARCHAR2(10), 
  DELAYWEEKS VARCHAR2(20)
   );
  
insert into TBLPAYMENTS (SID, PAYMENTTIME, PRODUCTID, AMOUNT, PAYMENTSTATUS, SALES, REGION, DELAYWEEKS)
values ('S-1', to_date('02-01-2019 12:20:30', 'dd-mm-yyyy hh24:mi:ss'), 'P-1', 30, 'Paid', '张三', '华南', '每日按要求更新');
insert into TBLPAYMENTS (SID, PAYMENTTIME, PRODUCTID, AMOUNT, PAYMENTSTATUS, SALES, REGION, DELAYWEEKS)
values ('S-2', to_date('02-02-2019 12:20:30', 'dd-mm-yyyy hh24:mi:ss'), 'P-2', 60, 'Waiting', '张三', '华南', '每日按要求更新');
insert into TBLPAYMENTS (SID, PAYMENTTIME, PRODUCTID, AMOUNT, PAYMENTSTATUS, SALES, REGION, DELAYWEEKS)
values ('S-3', to_date('02-03-2019 22:20:30', 'dd-mm-yyyy hh24:mi:ss'), 'P-3', 90, 'Paid', '李四', '华东', '每日按要求更新');
insert into TBLPAYMENTS (SID, PAYMENTTIME, PRODUCTID, AMOUNT, PAYMENTSTATUS, SALES, REGION, DELAYWEEKS)
values ('S-4', to_date('04-03-2019 15:20:30', 'dd-mm-yyyy hh24:mi:ss'), 'P-1', 100, 'Waiting', '张三', '华南', '每日按要求更新');
insert into TBLPAYMENTS (SID, PAYMENTTIME, PRODUCTID, AMOUNT, PAYMENTSTATUS, SALES, REGION, DELAYWEEKS)
values ('S-5', to_date('02-04-2019 12:20:30', 'dd-mm-yyyy hh24:mi:ss'), 'P-2', 200, 'Waiting', '李四', '华南', '每日按要求更新');
insert into TBLPAYMENTS (SID, PAYMENTTIME, PRODUCTID, AMOUNT, PAYMENTSTATUS, SALES, REGION, DELAYWEEKS)
values ('S-6', to_date('22-05-2019 17:20:30', 'dd-mm-yyyy hh24:mi:ss'), 'P-3', 3000, 'Paid', '张三', '华东', '每日按要求更新');
  

2.tblproduct表格创建语句

---- tblproduct 创建语句: 
 CREATE TABLE TBLPRODUCT 
   (SID VARCHAR2(10),
  PRODUCTNAME VARCHAR2(20), 
  UNITPRICE NUMBER(20,0), 
  STATUS VARCHAR2(10)
   );

insert into TBLPRODUCT (SID, PRODUCTNAME, UNITPRICE, STATUS)
values ('P-1', '商品A', 10, 'Active');
insert into TBLPRODUCT (SID, PRODUCTNAME, UNITPRICE, STATUS)
values ('P-2', '商品B', 20, 'Active');
insert into TBLPRODUCT (SID, PRODUCTNAME, UNITPRICE, STATUS)
values ('P-3', '商品C', 30, 'Inactive');

于是,第一题的解题答案:


WITH T AS 
(
SELECT NVL(TO_CHAR(TPAY.PAYMENTTIME, 'MM'),'TOTAL') AS 月份,
       TPRO.PRODUCTNAME,
       SUM(TPAY.AMOUNT) AS 金额
  FROM TBLPAYMENTS TPAY
  JOIN TBLPRODUCT TPRO
    ON TPAY.PRODUCTID = TPRO.SID
 WHERE TO_CHAR(TPAY.PAYMENTTIME,'YYYY') = '2019'
 GROUP BY ROLLUP(TO_CHAR(TPAY.PAYMENTTIME, 'MM')), TPRO.PRODUCTNAME

)


--- 数字和字符合并显示, 要加双引号

SELECT * FROM T PIVOT(MAX(金额) FOR 月份 IN ('TOTAL' AS YTD,
                                '01' AS "1月",'02' AS "2月",'03' AS "3月",
                                                                '04' AS "4月",'05' AS "5月",'06' AS "6月",
                                                                '07' AS "7月",'08' AS "8月",'09' AS "9月",
                                                                '10' AS "10月",'11' AS "11月",'12' AS "12月"));

结果如下图所示:
注意: 当有数字,又有字符串,记得用""括起来。
【PL/SQL 练习题6】 银行日常业务_第2张图片

第二题:
【PL/SQL 练习题6】 银行日常业务_第3张图片

解题思路:
1.按区域按月份排名,既要分组又要排序 -- 排序分析函数。
2.按照两个字段条件排序,Partition by 两个字段。
3.按照销售金额的大小排序,聚合函数 + group by + order by
4.没有排序字段出现,创建新字段,全表嵌套子查询,倒叙排序后等于1。

第一步至少要得出以下表格:

【PL/SQL 练习题6】 银行日常业务_第4张图片

 SELECT REGION AS 区域名称,
           TO_CHAR(PAYMENTTIME, 'YYYY-MM') AS 年月,
           SALES AS 销售名称,
           SUM(AMOUNT) AS 销售额
    FROM tblPayments
    GROUP BY REGION,
             TO_CHAR(PAYMENTTIME, 'YYYY-MM'),
             SALES

第二步套用子查询和分析函数,取排名第一
【PL/SQL 练习题6】 银行日常业务_第5张图片

SELECT 区域名称, 年月, 销售名称 
FROM(
  WITH T AS(
    SELECT REGION AS 区域名称,
           TO_CHAR(PAYMENTTIME, 'YYYY-MM') AS 年月,
           SALES AS 销售名称,
           SUM(AMOUNT) AS 销售额
    FROM tblPayments
    GROUP BY REGION,
             TO_CHAR(PAYMENTTIME, 'YYYY-MM'),
             SALES)
                 


   --- 根据两个字段分组排序,在实现在每个区域下的每个月的排名。           
  SELECT T.*,
         ROW_NUMBER() OVER (PARTITION BY 区域名称, 年月 ORDER BY 销售额 DESC) AS 排名
  FROM T
 ORDER BY 年月)
WHERE 排名=1;
 
 

第三题:
t4.png

解题思路:
1.Case When 分条件判断;
2.UPDATE 表名 SET 字段 = 新值 WHERE 列名称 = 某值;


业务2:
表格如下:剔除第一单实付金额小于100元的订单
再从剩下的订单钟找出某个用户第二次以来的复购订单。

【PL/SQL 练习题6】 银行日常业务_第6张图片

解题思路:
1.先找出第一笔订单是100元以下的,作为一张临时表。
与源表两张表用补集Minus计算出第二次复购的。
2.Case When 二分法,找出小于100元的则赋值为0,否则为1,最后再筛选出所有1的结果。
3.两个条件是不是第一单,是不是小于100元。

方法1(比较传统):

SELECT * FROM T_PAY;

SELECT T.*, ROW_NUMBER() OVER(PARTITION BY T.CUS_ID ORDER BY PAY_TM) AS RN
  FROM T_PAY T
MINUS  
SELECT *
  FROM (SELECT T.*,
               ROW_NUMBER() OVER(PARTITION BY T.CUS_ID ORDER BY PAY_TM) AS RN
          FROM T_PAY T)
 WHERE RN = 1
   AND PAY_AMT < 100;

方法2(比较讨巧):

--- 思路: 用CASE WHEN 二分法判断,如果不满足的,则返回0,如果满足的则返回1
---  套用子查询,筛选符合题意的内容;
SELECT *
  FROM (SELECT T.*,
               CASE
                 WHEN RN = 1 AND PAY_AMT < 100 THEN 0
                 ELSE 1
               END FLAG
          FROM (SELECT T.*,
                       ROW_NUMBER() OVER(PARTITION BY T.CUS_ID ORDER BY PAY_TM) AS RN
                  FROM T_PAY T) T) T1
 WHERE T1.FLAG = 1;

方法3(比较推荐):

 SELECT * FROM (
 SELECT T.*,ROW_NUMBER()OVER(PARTITION BY T.CUS_ID ORDER BY T.PAY_AMT) AS RN
       FROM T_PAY T
 )A WHERE RN!=1 OR A.PAY_AMT > 100;
 

你可能感兴趣的:(oracle,plsql)