• oracle系列(一)-- 常用脚本汇总--过程、函数、流程控制、触发器


      1 select  *  from emp;
      2 
      3 --分页查询
      4 select rownum,empno from  emp where rownum>0;
      5 select *  from(
      6        select  empno,rownum r from emp 
      7 )e where r>10 and r<13
      8 
      9                   ---PL/SQL入门--声明-type-rowtype-record-view-table
     10 
     11 /*
     12   PL/SQL语言
     13 */
     14 
     15 declare  --定义部分
     16    v_name varchar2(20);--变量的 声明: 变量名 变量类型
     17    v_sal number(10,2);
     18 begin--执行部分
     19   v_name := 'lxm'; --变量
     20   select ename ,sal into v_name,v_sal from emp where empno=&eno;--这里empno不写死的话,后边可以自己输入值
     21   dbms_output.put_line(v_name||v_sal);
     22 end;
     23 select  *  from emp where empno=&eno;
     24 
     25 
     26 
     27 /*
     28   万能类型
     29   将一个字段的类型作为一个数据类型
     30 */
     31 declare
     32     v_name emp.job%type; --定义v_name的数据类型和emp里的job字段类型相同
     33 begin
     34 
     35   select job  into v_name from emp  where empno=7788;
     36   dbms_output.put_line(v_name);
     37 end;
     38 
     39 
     40 /*
     41   万能类型
     42   将一行数据分别对应的类型作为一个打的数据类型
     43 */
     44 declare
     45    v_rowdemo emp%rowtype; --定义变量的数据类型和emp整行的数据类型
     46                           --那么emp有几个字段,v_rowdemo就会有几个字段
     47 begin
     48    select * into v_rowdemo from emp where empno=7788;
     49    dbms_output.put_line(v_rowdemo.ename||v_rowdemo.sal);--输出时使用变量.列名,直接输出整个变量会报错
     50  end;
     51 
     52 
     53 
     54 
     55 /*
     56  record,是自己声明的一种一行多列的数据类型
     57   使用一个变量,存储员工姓名和员工所在的部门名称
     58 
     59 */
     60 
     61 declare
     62  --emp_info_record 是一个类型  相当于varchar
     63    type emp_info_record is record(
     64         v_ename varchar(30),
     65         v_dname varchar2(30)
     66    );
     67   v_emp_info  emp_info_record;
     68 begin
     69  
     70 
     71 /*
     72   视图,
     73   相当于一个虚表,查询结果被放在视图里。下次查东西可以直接从这里边查
     74   scott默认没有创建视图的权限,所以要先以管理员身份登录给他赋权限
     75   grant create view to scott
     76   授权之后,scott用户就有了创建视图的权限
     77 */
     78 create view myview --create view  视图名
     79 as
     80 select empno,ename,sal from emp;
     81 --视图创建成功,可以从其中查数据
     82 select  empno  from  myview
     83 
     84 
     85 /*
     86    %record
     87 */
     88 declare
     89    type emp_record_type is record( --定义record
     90         ename emp.ename%type,
     91         sal emp.sal%type,
     92         comm emp.comm%type,
     93         total_sal emp.sal%type
     94    );
     95    v_emp_record emp_record_type; --声明一个record
     96 begin 
     97    select ename,sal,nvl(comm,0),sal+nvl(comm,0) --执行查询
     98    into v_emp_record
     99    from emp where empno=7369;
    100    dbms_output.put_line('姓名:'||v_emp_record.ename);
    101    dbms_output.put_line('薪水:'||v_emp_record.sal);
    102    dbms_output.put_line('奖金:'||v_emp_record.comm);
    103    dbms_output.put_line('总薪水:'||v_emp_record.total_sal);
    104 end;
    105 
    106 
    107 /*
    108    table数据类型
    109 */
    110 declare --定义一个table类型
    111    type dept_table_type is table of dept%rowtype--type table名字 is table of table类型 
    112    index by binary_integer; --将主键定义为二进制
    113    v_dept_table dept_table_type;
    114 begin
    115   select * into v_dept_table(0) from dept where deptno=10; --每次将一行主句赋值给table的另一行
    116   select * into v_dept_table(1) from dept where deptno=20;                              
    117   dbms_output.put_line('部门编号: '||v_dept_table(0).deptno||'  部门名称:'
    118                        ||v_dept_table(0).dname||'  位置:'||v_dept_table(0).loc);
    119   dbms_output.put_line('部门编号: '||v_dept_table(1).deptno||'  部门名称:'
    120                        ||v_dept_table(1).dname||'  位置:'||v_dept_table(1).loc);
    121   end;
    122 
    123 
    124 /*
    125   批量赋值 
    126   bulk:体积、大块
    127   collect:搜集、收集
    128   bulk collect into 相当于批量赋值
    129 */
    130 declare
    131   type v_dept_table is table of dept%rowtype
    132   index by binary_integer;
    133   v_dept v_dept_table;
    134 begin
    135   --select *  bulk collect into 表明 from 表名
    136   select *  bulk collect into v_dept from dept; --将所有的数据赋值给v_dept
    137   dbms_output.put_line(v_dept(2).dname); --取的时候,取自己想要的
    138 end;
    139 
    140 
    141 
    142                               --------------流程控制-----------------------
    143 /*
    144   if循环
    145   相当于 if循环
    146   if(n==5)
    147       输出n
    148       
    149   ---
    150   if 
    151      条件1 then
    152          执行语句1;
    153      elsif 条件2 then
    154          执行语句2;
    155      else
    156        执行语句;  
    157    end if;
    158 */
    159 declare
    160    v_n number := 4;
    161 begin
    162   if v_n=5 then
    163     dbms_output.put_line(v_n);
    164   elsif v_n=4 then  --注意oracle里没有else if,只有elsif,不要错误写成elseif
    165     dbms_output.put_line('44444is'||v_n);
    166    else
    167      dbms_output.put_line('未知数');
    168   end if;
    169 end;
    170 
    171 
    172 
    173 /*
    174   case循环
    175   case 变量
    176     when 条件 then 执行语句;
    177     when 条件 then 执行语句;
    178     else 执行语句
    179    end case
    180 */
    181 
    182 declare
    183   v_deptno dept.deptno%type:=&deptno;
    184 begin
    185   case v_deptno
    186     when 10 then dbms_output.put_line('我的部门是:  '||v_deptno);
    187     when 20 then dbms_output.put_line('我的部门是:  '||v_deptno);
    188     when 30 then dbms_output.put_line('我的部门是:  '||v_deptno);
    189     when 40 then dbms_output.put_line('我的部门是:  '||v_deptno);
    190     else dbms_output.put_line('不存在该部门');
    191   end case;
    192  end;
    193 
    194 
    195 /*
    196  loop循环
    197  loop
    198    [exit when 条件]
    199  end loop;
    200  
    201  相当于do while循环,先执行一次,再判断是否满足条件
    202 */
    203 declare
    204  v_n number := 10;
    205 begin
    206   loop
    207     v_n := v_n-1; --oracle中没有 v_n--;没有自减
    208     dbms_output.put_line(v_n);
    209     --exit when v_n=0;
    210     if v_n=0 then exit;
    211     end if;
    212    end loop;
    213 end;
    214 
    215 
    216 /*
    217    loop 循环和for循环嵌套
    218    for n in 1..10表明n在[1,10]之间
    219    reverse 表示降序排列,
    220 */
    221 
    222 
    223 begin
    224  -- for n in 1..10 
    225     for n in reverse 1..10 --inverse代表逆序
    226     loop
    227       dbms_output.put_line(n);
    228      end loop;
    229   end;
    230 
    231 
    232 /*
    233 `相当于while循环
    234   while 条件 loop
    235     执行语句
    236   end loop
    237 */
    238 declare 
    239   v_n number := 10;
    240 begin
    241   while v_n>0 loop
    242     v_n := v_n-1;
    243     dbms_output.put_line('n是: '||v_n);
    244   end loop;
    245 end;
    246 
    247 
    248                                         --游标--
    249 /*
    250    定义游标:cursor 游标名字 is select_statement
    251    打开游标:open  游标名字
    252   提取游标数据:fetch 游标名字 into 
    253   关闭游标:close 游标名字
    254   
    255   显式游标:处理select语句返回的多行数据
    256           1):显示游标属性:
    257              %ISOPEN:游标是否打开,打开为true,关闭为false
    258              %FOUND:检查是否从结果集中提取到数据,提取到为true,没有提取到为false
    259              %NOTFOUND:与%FOUND相反,此外 还可以用这个属性退出循环
    260              %ROWCOUNT返回当前位置已经提取到的实际行数
    261              属性使用方法 游标名+属性
    262              
    263            2):带有参数的游标,多处使用游标,传入不同的参数时,获得不同的结果
    264              cursor 游标名字 (参数名字,参数类型) is select_statement
    265              定义时必须声明参数的数据类型,而不能定义参数的长度
    266   隐式游标:用来处理select into 和DML语句
    267 */
    268 
    269 --显示游标
    270 --eg1:
    271 declare
    272   v_dept dept%rowtype;
    273   cursor cur_dept is select  *  from dept where deptno>10; --声明游标
    274 begin
    275   open cur_dept;  --打开游标
    276   loop
    277     fetch cur_dept into v_dept; --提取数据
    278     exit when cur_dept%NOTFOUND;
    279     dbms_output.put_line('编号:'||v_dept.deptno||' 名字:'||v_dept.dname||'  位置:'||v_dept.loc);
    280   end loop;
    281   close cur_dept;
    282 end;
    283 
    284 
    285 --eg2:用table结构提取游标数据
    286   declare
    287       type v_dept is table of dept%rowtype 
    288       index by binary_integer;  --声明表结构
    289       cursor cur_dept is select  *  from dept;--声明游标
    290       v_dept_table v_dept;--声明一个变量是v_dept类型的
    291   begin
    292      open cur_dept;
    293      fetch cur_dept bulk collect into v_dept_table;--将游标中的数据批块放入到表里
    294      close cur_dept; --数据已经拿到,就可以关闭游标
    295      for i in v_dept_table.first..v_dept_table.last loop--遍历一个表结构就用 for in
    296        dbms_output.put_line('位置:' ||v_dept_table(i).loc);--循环输出,就用下表
    297      end loop;
    298   end;
    299 
    300 --eg3:带参数的游标
    301   declare
    302      cursor cur_dpet(para_deptno number) is  --定义有参数的游标
    303      select dname, loc  from dept where deptno=para_deptno;--将参数作为查询条件
    304      dept_record cur_dpet%rowtype; --定义一个变量,类型和游标的行类型一直
    305   begin
    306     open cur_dpet(20); --打开游标,同时把参数传进去
    307     loop
    308         fetch cur_dpet into dept_record; --提取数据,放到dept_record里
    309         exit when cur_dpet%notfound;
    310         dbms_output.put_line(dept_record.dname||'  '||dept_record.loc);  
    311     end loop;
    312     close cur_dpet; --关闭游标
    313   end;
    314   
    315   
    316 
    317 --eg4:for循环简化游标遍历,
    318   --用for循环时,oracle会隐式打开游标并且提取数据后关闭,
    319   declare 
    320     cursor cur_dept is select *  from dept; 
    321   begin
    322     for cur_row in cur_dept loop --n相当于游标中存储的数据,所对应的一个个的行数据的对象
    323       dbms_output.put_line('行编号是'||cur_dept%rowcount||'   部门名字是:'||cur_row.dname);
    324     end loop;
    325   end;
    326   
    327 --eg5:使用for循环时,游标可以更简化,声明、打开、关闭、都可以省略
    328 
    329   begin
    330     for dept_row in(select dname,loc from dept) loop
    331       dbms_output.put_line('部门位置是--:'||dept_row.loc);
    332     end loop;
    333   end;
    334   
    335  --游标变量--  
    336  /*
    337   游标和游标变量的区别
    338     1):游标是数据库中一个命名的工作区,与固定的SQL语句相关联,在编译时是已知的,
    339         是静态的,永远指向一个相同的查询工作区
    340                  ---简而言之,对应的SELECT语句,在游标定义的时候,在declare声明部分就已经写好了
    341     2):游标变量
    342          A:语法
    343                  type ref_type_name IS REF CURSOR; --先定义一个游标变量
    344                  v_ref ref_type_name; 再声明一个变量,这个变量的类型是 上边定义好的游标变量的类型
    345          B:游标变量在运行时可不同的SQL语句先关联,这样运行不同的SQL语句就可以引用不同的工作空间
    346  */ 
    347   
    348  --eg:游标变量
    349  declare
    350          type ref_type_name is ref cursor;--定义
    351          cur_emp ref_type_name; --定义游标的类型,是个游标变量
    352          v_row emp%rowtype; --后边用,用来存储游标中的一行数据
    353  begin
    354    open cur_emp for select  *  from emp where empno=7369; --open for ,打开
    355   loop
    356     fetch cur_emp into v_row ;
    357     exit when cur_emp%notfound;
    358     dbms_output.put_line('行号:'||cur_emp%rowcount||'   部门编号:'||v_row.empno||';部门名字:'||v_row.ename);
    359   end loop;
    360  end;
    361  
    362  /*
    363   隐式游标
    364       跟显示游标不同的是,游标的定义,打开,数据提取,关闭,都是由数据库隐式来操作的
    365       属性只有两个  SQL%FOUND, SQL%NOTFOUND
    366  */
    367  
    368  declare
    369       v_empno number(10) := 7369;
    370  begin
    371    update emp set ename='小绿绿' where empno=v_empno;
    372    if sql%found then  --判断隐含游标sql是否有影响行数
    373      dbms_output.put_line('修改成功');
    374     else
    375         dbms_output.put_line('修改失败,员工不存在');
    376     end if;
    377  end;
    378 
    379  
    380                               ------触发器---
    381 /*
    382   create or replace trigger 触发器名字
    383   before[after]
    384   事件[update or delete or insert]
    385   on 表名
    386 
    387   :new表和:old表
    388   只有用了 for  each  row 才能用new ,old
    389   new和old 相当于虚表
    390   insert:新增,把新数据存到:new,再执行新增
    391   delete:删除,把老数据存到:old,再执行删除
    392   update:修改,把老数据存到:old,把新数据存到:new,判断:old和:new表中数据是否一样,
    393                 一样不执行任何修改,不一样执行修改
    394   
    395   create or replace  trigger 触发器名字
    396   before[after] --触发时机
    397   update [delete、insert、select]操作的动作
    398   on 表名
    399   for each row --没触发一行就触发一次 触发器
    400   begin
    401     if(updating) then
    402         执行语句
    403     end if; 
    404   end;
    405 */
    406 create or replace trigger  tri_dept
    407 after --触发时机,before为之前,after为之后
    408 update or delete  or insert  --哪些事件会触发 触发器
    409 on dept  --对哪张表操作
    410 for each row --每一行操作时都出发,如果不写,比如对整个表都进行修改,但只触发一次,
    411              --写了这一句,sql语句设计到几行,就出发几次事件
    412 begin
    413    if(updating) then 
    414        dbms_output.put_line('你出发的操作是update旧数据是: '||:old.loc);--old是原表中的数据
    415        dbms_output.put_line('你出发的操作是update新数据是: '||:new.loc);--new是修改后的新数据
    416    end if;
    417     if(deleting) then
    418        dbms_output.put_line('触发器触发delete...');
    419     end if;
    420     if(inserting) then
    421        dbms_output.put_line('触发器触发insert');
    422     end if;
    423 end;
    424 
    425 
    426 
    427                                                  --存储过程--procedure
    428 /*
    429                  第一种 无参数的过程,
    430     
    431     语法:
    432     create or repalace procedure 名字
    433     is
    434            声明部分
    435     begin
    436       执行部分
    437       exception
    438         异常处理部分
    439      end;
    440 */
    441 
    442 --一个没有exception的无参存储过程
    443  create or replace  procedure pro_emp_sal--注意这里,过程名字后边没有()
    444  is
    445  begin
    446    update dept set loc='sahgnhai' where deptno = 20;--
    447   end;
    448 
    449 --一个有exception的无参存储过程  
    450  create or replace procedure pro_sel_sal
    451  is
    452     v_sal number(10);
    453  begin
    454    select sal into v_sal from emp where deptno=70;
    455    dbms_output.put_line(v_sal);
    456    exception
    457      when no_data_found then
    458        dbms_output.put_line('员工编号不存在');
    459  end;
    460  
    461  drop procedure pro_sel_sal; --删除 存储过程 drop procedure 过程名字
    462  --调用无参过程的三种方法
    463   call pro_sel_sal();--call 过程名字();
    464   exec pro_emp_sal; --exec 过程名字;  但是这种方式只有再sqlplus 或者命令窗口中可以用,再plsql中不可以用
    465   begin             --begin 过程名字; end;
    466        pro_sel_sal;
    467   end;
    468 select *  from emp;
    469 update dept set loc='aa' where deptno='40'
    470 
    471 
    472 /*
    473             有参的存储过程(如果不指定参数模式,默认为输入参数)
    474             
    475   有三种参数形式:
    476     1):in传参 ,定义被in,输入参数,这个in可以不写,默认就是输入传参
    477     2):out传参,该参数是用来输出的
    478     3):in out 传参  该参数既用来输入,也用来输出
    479    
    480   有三种参数传递的形式
    481    1):按照参数顺序依次放入参数
    482    2):用=>传递参数 eg: pro_emp_sal(v_no=>'7369'); 注意,变量在前边,传过来的值在后边
    483    3):混合方式传参,参数1,放在第一个位置,后边的参数用 =>传递参数
    484    不管是哪种传参方式,被in,或者out,或者 inout修饰的参数,在调用的时候一定要声明
    485 */
    486 
    487 /*
    488   in传参 创建存储过程
    489 */
    490  create or replace procedure pro_emp_sal(v_no in emp.empno%type)
    491  is
    492   v_sal number(10);
    493  begin
    494    select sal into v_sal from emp where empno=v_no;
    495    dbms_output.put_line(v_no ||' 的工资是:'||v_sal);
    496     exception  
    497       when no_data_found  then
    498         dbms_output.put_line('请输入正确的员工编号');
    499  end;
    500      --调用 存储过程
    501 declare
    502  v_no number(10);    
    503 begin
    504  v_no := &empno;
    505  pro_emp_sal(v_no);
    506 end;
    507 
    508 
    509 /*
    510  out 传递参数的存储过程
    511 */
    512 create or replace procedure pro_sel_al(v_sal out emp.sal%type)
    513 is
    514 begin
    515   select sal into v_sal  from emp where empno=7369;
    516   dbms_output.put_line(v_sal);
    517 end;
    518    
    519 --调用存储过程
    520 declare
    521  v_sals number(10);
    522 begin
    523   pro_sel_al(v_sal=>v_sals);-- =>传递参数
    524 end;
    525 
    526 /*
    527   in,out分别传递参数,的存储过程
    528 */
    529 create or replace procedure pro_emp_sal(v_no in emp.empno%type, v_sal out emp.sal%type)
    530 is
    531 begin
    532   select sal into v_sal from emp where empno=v_no;
    533   dbms_output.put_line('工资是: '||v_sal);
    534 end;
    535 
    536 --调用 存储过程
    537 declare
    538    v_no emp.empno%type;
    539    v_sal emp.sal%type;
    540 begin
    541   v_no := &no; --输入的变量一定要在执行的时候定义出输入
    542  pro_emp_sal(v_no,v_sal); --按照参数位置传参
    543 
    544 end;
    545 
    546 /*
    547   in out传递参数
    548   在这里 in out 修饰同一个变量,则这个变量既是输入变量也是输出变量
    549 */
    550 create or replace procedure pro_emp_sal(empnum in out number)
    551    is
    552  begin
    553    select  sal into empnum from emp where empno=empnum;
    554  --  dbms_output.put_line(v_no ||'的工资是: '|| empnum);
    555  end;
    556 
    557 --调用存储过程
    558 declare
    559  in_outnum emp.empno%type;
    560 begin
    561   in_outnum := &no;
    562   pro_emp_sal(in_outnum);
    563   dbms_output.put_line('工资是: '||in_outnum);
    564 end;
    565 
    566                          
    567 
    568                              ----开发函数----
    569 /*
    570    create or replace function 名字()
    571       return 返回值类型; --一定要有的
    572      is[as]
    573        变量声明部分
    574     begin
    575              执行语句
    576              return 语句;  --一定要有
    577        exception
    578     end;
    579 */
    580 
    581 create or replace function getsum(m number , n number)
    582   return number
    583   is
    584   mn number;
    585 begin
    586   mn := m+n;
    587   return mn;
    588 end;
    589        
    590 --调用function
    591 declare
    592   m number;
    593   n number;
    594   mn number;
    595 begin
    596   m := &m;
    597   n := &n;
    598   mn := getsum(m,n);
    599   dbms_output.put_line(mn);
    600 end;
    601 
    602                             ---过程与函数的异同-------
    603 /*
    604     1:相同点
    605         1):都用in模式传入数据,都用out模式传出数据
    606         2):参数的传递都可以用位置传递法和名称传递法
    607         3):输入参数时都可以有默认值,都可以传值
    608         4):都有声明部分、执行部分、异常部分
    609      2:不同点
    610         1):没有返回值,或者只输出一个值时用function
    611         2):输出多个值时用存储过程
    612         3):输出多个值时也可以用function,但是这被认为是不规范的写作习惯
    613         4):一般存储过程用来完成某个动作,function用来计算或者返回一个值
    614 */
    615                         --包--
    616 /*
    617   包存在的意义:满足oracle种模块化的需求,在大型项目中,每个模块有很多的过程和函数,不便于管理和维护
    618   甚至造成误删,所以分包后便于管理,
    619   解决了命名的问题,不同包里的函数或者过程可以命名相同
    620   
    621   
    622   包头--语法:  --包头规范相当于java中的接口
    623         create or replace package 包名 is
    624                function 函数名() return 返回类型;
    625                  procedure 过程名();
    626         end 包名;
    627    
    628   包体--语法:   --包体规范相当于java中的接口实现
    629   create or replace package body 包名 is
    630          写function; (这里直接写,没有create or  replace 这句话)
    631          写过程;(这里直接写,没有create or  replace 这句话)
    632   end 包名
    633   
    634   --调用方法:
    635   decalre
    636     声明部分
    637    begin
    638      包名.函数名;
    639      包名.过程名;
    640    end;
    641 */
    642 --包头
    643 create or replace package my_package is
    644        function plus(m number, n number)  return number;
    645        procedure cheng(x number, y number, xy out number);
    646 end my_package;
    647 
    648 --包体
    649 create or replace package body my_package is
    650        function plus(m number, n number) return number
    651          is  nm number;
    652           begin
    653                nm := m+n;
    654            return nm;
    655           end;
    656        procedure cheng(x number, y number, xy out number)
    657            is 
    658            begin
    659               xy := x+y;
    660               dbms_output.put_line(xy);        
    661            end;
    662 end my_package;
    663 --调用包里的方法
    664 declare
    665     cc number(10);
    666 begin
    667    -- cc:= my_package.plus(11,22);
    668     --dbms_output.put_line('两个数的和是:'||cc);
    669     my_package.cheng(11,2,xy=>cc);
    670 end;
    671 
    672 /*
    673     数据字典:user_source
    674     跟用户相关的子程序和和源代码被存在里边
    675     假如要查看 包名为my_package,的源代码
    676     select  text  from user_source  where name='my_package';
    677     删除子程序 :drop procedure proce_anme
    678     删除包体: drop package body 包名
    679     删除包头和包体 drop pacakge 包名
    680 */
    681 select text from user_source where name='MY_PACKAGE';
    682 
    683                   --------游标--------
    684 
    685 /*
    686 
    687    1:游标是啥?
    688 
    689     游标是指向上下文区的指针,它为应用提供了一种对具有多行查询结果集的数据,中
    690 
    691     的每一行分别进行单独处理的方法
    692 
    693 */
    694 
    695 declare
    696 
    697   v_dept dept%rowtype;
    698 
    699   cursor dept_cursor is select * from dept where deptno>10;  --定义游标
    700 
    701 begin
    702 
    703     open dept_cursor;  --打开游标
    704 
    705     loop
    706 
    707       fetch dept_cursor into v_dept;  --提取数据
    708 
    709       exit when dept_cursor%notfound;  --判断循环退出条件
    710 
    711       dbms_output.put_line('编号:'||v_dept.deptno
    712 
    713    ||'  名称:'||v_dept.dname||'  地址:'||v_dept.loc);
    714 
    715     end loop;
    716 
    717     close dept_cursor;  --关闭游标
    718 
    719 end;
    720 
    721  
  • 相关阅读:
    django之表多对多查询
    Django之ORMselect_related和prefetch_related
    django中用户登入时初始化session中保存的数据
    django中间件判断用户有无权限访问当前的url
    django中自定议rbac权限model类
    django中的inclusion_tag配置和实现
    docker命令
    JS设置cookie、读取cookie、删除cookie
    MySQL Community Downloads
    44个CSS3制作的形状图形
  • 原文地址:https://www.cnblogs.com/coisini/p/9768740.html
Copyright © 2020-2023  润新知