Oracle总结及Mysql的分页查询

Oracle总结及Mysql的分页查询

一、Mysql的分页查询

  • limit接受一个或两个数字参数,参数必须是一个整数常量。第一个参数指明从哪条记录开始,第二个参数指明页数大小

    • 示例

      -- 查询员工表前3名的员工的编号和姓名
      select empno,ename from emp limit 3;
      -- 或者
      SELECT empno,ename FROM emp LIMIT 0,3;
      查询员工表第三页的员工信息信息(假设每页显示4条,总共有14条)
      SELECT empno,ename FROM emp LIMIT 8,4;

      MySQL的分页语句中 LIMIT后面的 第一个参数是(page-1)*pagesize 第二个参数是pagesize 其中page表示页码,pagesize表示每一页显示的最大记录数

二、Oracle总结

(一)数据库模型、关系模型、三范式、有效性和安全性的实现

  1. 数据库模型

    • 关系型数据模型:Oracle,MySql,SQLServer

    • 非关系型数据模型:H2,Redis,MongoDB

  2. 关系模型

    • 关系模式:是静态的稳定的

    • 关系:关系是关系模式在某一时刻的状态或内容,关系是动态的

    • 关系模型:关系模型是指用二维表的形式表示实体和实体间联系的数据模型

  3. 数据库设计步骤

    • doc->从doc文档中找出实体->将实体和属性转换为表格

  4. 三范式

    • 1NF:字段不可拆分

    • 2NF:表中要有主键

    • 3NF:表中不能有别的表的非主键列

  5. 数据库的有效性和安全性通过约束来实现

    • 主键约束:唯一确定一条记录,记录不重复,不能为空

    • 唯一约束:唯一确定一条记录,记录不重复,可以为空

    • 默认约束:有些列不能为空,必须有值,但客户可能忘记赋值,此时用默认约束强制给空记录赋值一个默认值,保证数据的有效性,完整性

    • 检查越俗:让数据有效,不能出现意外的数据

    • 外键约束:如果依赖的表中没有相应的主键记录,则当前表就无法添加记录,这就是外键依赖,当然要删除依赖表中的记录时,如果记录有被依赖的情况,则要么报错不能删除,要么级联删除当前表中的记录,保证了数据的安全,避免了依赖不存在的问题。

(二)SQL语言的分类:DDL、DML、DQL、TCL、DCL

  1. SQL语言的描述和作用

    • SQL语言是一种结构化查询语言

    • 作用是用来管理关系型数据库

  2. SQL语言的分类

    • DDL(Data Definition Language):数据定义语言

    • DML(Data Manipulation Language):数据操纵语言

    • DQL(Data Query Language):数据查询语言

    • TCL(Transaction Control Language):事务控制语言

    • DCL(Data Control Language):数据控制语言

  3. DDL(数据定义语言)

    • 关键词:create、alter、drop

    • 表空间

      • 定义:表空间是存储数据的地方,存储数据库对象的地方,在磁盘上对应有数据文件

      • Oracle中默认有一个系统表空间和临时表空间,如果创建用户不指定用户的表空间,则默认把用户创建在系统表空间,系统表空间类似于windows的C盘,如果把所有软件安装在C盘是不合理的,Oracle中把用户分配在系统表空间也是不合理的,最理想的是一个用户一个表空间,在删除用户时可以删除表空间,这样管理比较好。

      • 表空间是虚拟的,可以无限大,数据文件是存储信息的载体

      • 临时表空间:数据库操作时临时使用,如排序,去重,统计等大数据时使用,小规模可以在内存中完成

      • 操作

        -- 授予管理员权限
        grant dba to user_test;
        -- 授予创建表空间的权限
        grant create tablespace to user_test;
        -- 创建表空间
        create tablespace sp1 datafile 'sp1.dbf' size 1m;
        -- 创建临时表空间
        create temporary tablespace tsp1 tempfile 'tsp1.dbf' size 2m;
        -- 创建用户时指定表空间和临时表空间
        create user user_test identified by user_test default tablespace sp1 temporary tablespace tsp1;
        -- 授予删除表空间权限
        grant drop tablespace to user_test;
        -- 删除表空间
        drop tablespace sp1 including contents and datafiles;
        -- 删除临时表空间
        drop tablespace tsp1 including contents and datafiles;
        -- 授予扩大表空间的权限
        grant alter database to user_test;
        -- 扩大表空间
        alter database datafile 'sp1.dbf' resize 2m;
        -- 授予在表空间增加数据文件的权限
        grant alter tablespace to user_test;
        -- 增加数据文件
        alter tablespacesp1 add datafile 'sp1_2.dbf' size 1m;
      • 数据类型

        number:数字类型
        integer:整数
        char:定长字符串
        varchar:变长字符串
        timestamp:时间戳
        blob:二进制数据
        clob:放大量的字符数据
        bfile:二进制文件
      • 对表的操作

        -- 创建表
        create table t1(id number);
        -- 增加一列
        alter table t1 add name char(4);
        -- 修改列的宽度
        alter table t1 modify name char(5);
        -- 删除一列
        alter table t1 drop column age;
        -- 增加系统默认名字的主键约束
        alter table t1 add primary key(id);
        -- 增加自己命名的主键约束
        alter table t1 add constraint t1_pk primary key(id);
        -- 删除主键
        alter table t1 drop primary key;
        -- 删除指定约束的主键
        alter table t1 drop constraint t1_pk;
        -- 增加唯一约束
        alter table t1 add constraint t1_uk unique(name);
        -- 增加默认约束
        alter table t1 modify age default 18;
        -- 增加检查约束
        alter table t1 add constraint t1_sex check(sex = 0 or sex = 1);
        -- 增加外键约束
        (什么都不写相当于no action,当子表有关联时删除父表记录会报错)
        alter table t1 add constraint t1_fk foreign key(clazz) references t_clazz(id);
        (设置为set null,删除父表记录时,把子表相应外键置为空)
        alter table t1 add constraint t1_fk foreign key(clazz) references t_clazz(id) on delete set null;
        (设置为cascade级联删除,删除父表时,子表相应的记录也会被删除)
        alter table t1 add constraint t1_fk foreign key(clazz) references t_clazz(id) on delete cascade;
        -- 删除外键约束
        alter table t1 drop constraint
        -- 删除表
        drop table t1;
        truncate table t1;
  4. DML(数据操纵语言)

    • 关键词:insert、delete、update

    • 对表中的数据进行操作

      -- 插入数据
      -- 不指定添加的字段
      insert into t_clazz values(1,'name1','');
      -- 指定添加的字段
      insert into t1(id,name,age,sex,clazz) values(3,'name1',10,0,1);
      -- 修改
      -- 修改所有记录
      update t_clazz set name='新名称';
      -- 修改指定记录
      update t_clazz set name='新名称1' where id=1;
      -- 删除
      delete from t_clazz where id=1;
  5. DQL(数据查询语言)

    • 关键词:select

    • 查询表中的信息

      -- 查询当前用户下所有表的信息
      select * from user_tables t;
      -- 查询当前表的所有字段信息
      select * from user_tab_columns where table_name='T_CLAZZ';
      -- 给表起别名
      as 或者是空格
      select sal,empno,ename,sal+100 sal2 from emp;
      -- 判断字段是否为空
      select sal from emp where sal is null;
      -- where过滤
      select empno,ename,sal from emp where sal>=3000;
      -- distinct去重
      -- 查询部门里有员工的部门号
      select distinct deptno from emp;
      -- distinct对后面的字段都进行过滤
      select distinct deptno,sal from emp;
      -- 排序,升序asc,降序desc
      -- 默认为升序
      select * from emp order by sal;
      -- 部门升序,部门中的员工工资降序
      select * from emp order by deptno asc,sal desc;
  6. TCL(事务控制语言)

    -- 提交事务
    commit;
    -- 事务回滚
    rollback;
    -- 设置标志
    savepoint p1;
    -- 插入数据
    insert into emp(empno) values(5);
    -- 回滚到标志处
    rollback to p1;
  7. DCL(数据控制语言)

    -- 创建角色
    create role 角色名;
    -- 分配权限
    grant select on class to 角色名;
  8. truncate,drop,delete三个的区别

    • truncate和drop属于DDL,针对的是表,delete属于DML,针对的是表中的数据

    • delete删除后不会释放空间,可以恢复数据,truncate和drop都会释放空间,不能恢复,truncate只删除表里的内容,drop删除的是全部,表上的所有对象都会删除掉

    • 有害化排序:delete->truncate->drop

(三)索引

  • 作用:快速查询数据

  • 优缺点:

    • 优点:DQL快速查询,为了保证查询速度,可以牺牲一定的空间和DML的操作时间

    • 缺点:占空间(在保存正常业务数据的同时,还要额外的存储索引信息),在维护正常业务数据的同时,还要维护索引的数据(占时间)

  • 什么情况下适合建立索引

    • 一个条件经常出现在where中,就要考虑是否要建立索引

    • 对于列中的数据区分度比较高的列也可以建立索引(反例:性别不适合)

    • 如果同时又多个查询条件,where c1=a and c2 = b,建立联合索引(c1,c2),索引中的列的顺序和where条件中的顺序尽量一致

      • 索引(c1,c2...)条件是where c1 = a and c2=b 这个是好的,条件是where c2=b这个不是特别理想,或者where c2=b and c1 = a这个也不好

  • 索引的分类

    • 聚集索引:会改变记录的物理位置

    • 非聚集索引:数据的顺序和它插入时的顺序一致,在索引中保存的是记录的rowid,找到索引,然后找到rowid,然后找到记录

(四)函数

  1. 单行函数

    • 字符函数

      -- 返回字符的ascii值:ascii函数
      -- 将连个字符或字符串拼接起来:concat函数
      -- 查找字符:instr函数
      -- 返回字符串的长度:length函数
      -- 将所有字符全部转换为小写:lower函数
      -- 将所有字符全部转换为大写:upper函数
      -- 去掉字符串中的空格:ltrim(去掉左边的空格),rtrim(去掉字符串右边的空格),trim(去掉字符串两边的空格)
      -- 替换字符:replace函数
      -- 截取字符中的一段:substr函数
    • 数字函数

      -- 求绝对值:abs函数
      -- 求大于或等于某个数的最小值:ceil函数
      -- 求小于或等于某个数的最大值:floor函数
      -- 四舍五入:round函数
      -- 截断函数:trunc函数
      -- 取余:mod函数
    • 日期函数

      -- 显示当前时间:sysdate关键字
      -- 在当前时间上增加一个月:add_months函数
      -- 求当前月的最后一天十几号:last_day函数
      -- 四舍五入日期:round函数
      -- 求月份差:months_between函数
      -- 求当前日期的下一个星期几是几号:next_day函数
      -- 提取员工的入职月份:extract函数
      -- 截断日期:trunc函数
    • 转换函数

      -- 转换成字符:to_char函数
      -- 转换成数字:to_number函数
      -- 转换成日期:to_date函数
  2. 多行函数

    • 统计函数

      -- 求最大值:max函数
      -- 求最小值:min函数
      -- 求员工的个数:count函数
      -- 求平均值:avg函数
      -- 求和:sum函数
    • 解决空值:nvl

      -- nv1(comm,0)函数:如果奖金(comm)为空的话,则转换为0
      -- nv2(comm,1,0)函数:如果奖金(comm)不为空,则转换为1,否则,转换为0
    • decode函数

      -- decode(job,'CLERK','店员');
      -- 注释:如果job=’CLERK‘,则显示为店员
    • 应用

      • 行转列

        CREATE TABLE resident(NAME VARCHAR(6) NOT NULL,r_month number(2) NOT NULL,sal NUMBER(8) NOT NULL);
        INSERT INTO resident VALUES('赵一',1,10000);
        INSERT INTO resident VALUES('赵一',2,10500);
        INSERT INTO resident VALUES('赵一',3,9000);
        INSERT INTO resident VALUES('赵一',4,10030);
        INSERT INTO resident VALUES('赵一',5,10500);
        INSERT INTO resident VALUES('赵一',6,10000);
        INSERT INTO resident VALUES('赵一',7,12000);
        INSERT INTO resident VALUES('赵一',8,10500);
        INSERT INTO resident VALUES('赵一',9,10800);
        INSERT INTO resident VALUES('赵一',10,10900);
        INSERT INTO resident VALUES('赵一',11,10010);
        INSERT INTO resident VALUES('赵一',12,10800);
        SELECT * FROM resident;
        DROP TABLE resident;
        -- 显示每个人每月的工资,以列的形式显示,2020我国的平均收入是40000元左右,显示该居民是否达到或拖后腿
        SELECT NAME,SUM(DECODE(r_month,1,sal)) 一月,
        SUM(DECODE(r_month,2,sal)) 二月,
        SUM(DECODE(r_month,3,sal)) 三月,
        SUM(DECODE(r_month,4,sal)) 四月,
        SUM(DECODE(r_month,5,sal)) 五月,
        SUM(DECODE(r_month,6,sal)) 六月,
        SUM(DECODE(r_month,7,sal)) 七月,
        SUM(DECODE(r_month,8,sal)) 八月,
        SUM(DECODE(r_month,9,sal)) 九月,
        SUM(DECODE(r_month,10,sal)) 十月,
        SUM(DECODE(r_month,11,sal)) 十一月,
        SUM(DECODE(r_month,12,sal)) 十二月,
        DECODE(TRUNC(SUM(sal)/40000),0,'拖后腿','合格') 是否合格
        FROM resident r GROUP BY NAME;
      • SQL递归的实现:

        -- SELECT *  FROM XX STRAT WITH 从什么地方开始  CONNECT BY PRIOR 递归条件
        -- 找id为1的子辈
        SELECT * FROM cow START WITH ID=1 CONNECT BY PRIOR ID = parent_id;

(五)序列

  1. 创建序列

    -- 创建序列:minvalue:最小值,maxvale:最大值,start with:开始值,increment:步长,cache:缓存
    -- 缓存有最大值限制:
    (最大值-最小值)/步长的绝对值,向上取整
    create sequence seq1
    minvalue 1
    maxvalue 9999999999
    start with 1
    increment by 1
    cache 20;
    -- 将序列改为循环使用:cycle
    alter sequence seq1 cycle;
  2. 序列的两个属性

    -- 下一个值
    select seq1.nextval from dual;
    -- 当前值
    select seq1.currval from dual;
  3. 删除序列

    drop sequence seq1;

(六)视图

  1. 引入视图的原因

    -- 有些表不能给程序员开放,DBA可以建一个视图,给程序员开放视图的权限,这样就可以间接来访问受限的表。
    -- 建立视图可以避免误修改数据的风险,对数据进行横向或纵向的保护
  2. 作用

    • 把SQL存储起来,运行方便

    • 可以有效的保护数据,对权限加以控制

  3. 特点

    • 视图是虚表,逻辑存在的(不是真实的,抽象的)

    • 视图关键字:view

    • 以SQL的形式存在

      create view v_emp as
      select * from emp;
    • 视图的定义:vw或v

  4. 建立视图

    -- 建立视图,若视图已经存在,就进行更新
    create or replace view v_emp as
    select * from emp;

    -- 创建带约束的视图:with check option
    CREATE OR REPLACE FORCE VIEW v_test AS
    SELECT * FROM emp WHERE empno>7788
    WITH CHECK OPTION;

    -- 创建只能查看的视图
    CREATE OR REPLACE FORCE VIEW v_test AS
    SELECT * FROM emp
    WITH READ ONLY;

    -- 视图涉及多个表
    CREATE OR REPLACE VIEW v_emp_dept AS SELECT empno,dname FROM emp e, dept d WHERE e.deptno=d.deptno;

    -- force:不存在权限也能创建视图
    CREATE OR REPLACE FORCE VIEW v_t1 AS SELECT * FROM user22.t1;
    -- 分配权限,能够查看此视图
    grant select on t1 to scott;
    -- 收回权限
    revoke select on t1 from scott;

    -- 查看视图
    SELECT * FROM v_emp_dept;
  5. 物化视图

    • 引入原因

      普通视图在执行SQL时要消耗性能,因为他们是一个SQL,物化视图执行时只查询自己的数据(不再进行计算)

    • 分类:ON DEMAND 、ON COMMIT

      • ON DEMAND :在需要时(在查询视图时)再从基表中更新数据到物化同步(物化视图的同步

      • ON COMMIT:在更新视图的同时,同步物化视图,物化视图始终是最新的。(维护数据效率低)

  6. SQL优化:索引和物化视图

(七)in和exists,PL/SQL编程

  1. in和exists执行顺序

    • in:由内而外,先执行子查询,将子查询作为结果集,再执行外查询

    • exists:由外而内,相当于loop循环,先从外表取出一条记录,然后进入子查询看这条记录是否符合条件,若符合,返回true,否则返回false,然后继续判断下一条记录

  2. in和exists例题

    • 员工表employee,有2个字段salary , deptid ,查询所有数据,按照部门号从高到低,工资从低到高顺序输出

      SELECT * FROM employee ORDER BY deptid DESC,salary;
    • 员工表employee,有2个字段salary , deptid ,查询各个部门中高于所有员工平均工资的人数:查询的结果列为: 部门,人数

      SELECT deptid 部门,COUNT(*) 人数 FROM employee WHERE salary>(
      SELECT AVG(salary) FROM employee) GROUP BY deptid;
    • 员工表employee,有2个字段salary , deptid ,查询出最高工资和最低工资的差是多少

      SELECT MAX(salary)-MIN(salary) FROM employee;
    • 用exists替换下面的sql中的in SELECT * FROM tb1 WHERE u_id IN (SELECT u_id FROM tb2 WHERE name = ‘张三’);

      SELECT * FROM tb1 WHERE EXISTS (
      SELECT * FROM tb2 WHERE NAME='张三' AND tb1.u_id=tb2.u_id);
  3. 当子查询返回的结果集很少时,采用in比较好;

    当子查询返回的结果集很多时,采用exists比较好

  4. PL/SQL编程

    • 区域:在Test window进行编程

    • 组成:

      • declare部分进行一些变量的定义

      • begin end;部分里面写执行程序

        declare 
         -- Local variables here
         -- 进行一些变量的定义
        i integer;
        begin
         -- Test statements here
         -- 执行程序在这里编写
         
        end;
    • 变量定义

      • 直接定义字段类型

          i integer;
        v_username VARCHAR(10);
      • 常量的定义

         pai CONSTANT NUMBER := 3.14;
      • 字段类型来源于表中

        v_empno emp.empno%TYPE;
      • 行变量的定义

         v_emprow emp%ROWTYPE;
    • 变量的赋值(用:=进行赋值)

      -- 在定义变量时进行赋值,或者在使用前进行赋值
      v_clazz NUMBER:=11;
      v_college NUMBER(10) DEFAULT 1;
      -- 在查询时进行赋值:将查询到的最高工资赋值给i
      SELECT MAX(sal) INTO i FROM emp;
      -- 行变量的赋值
      SELECT emp.empno,emp.ename INTO v_emprow.empno,v_emprow.ename FROM emp WHERE rownum=1;
    • 输出

      • dbms_output.put():输出到缓存

      • dbms_output.put_line():将缓存中的和要输出的进行输出

        dbms_output.put(1);
        dbms_output.put_line(2);
        dbms_output.put_line(v_username||'-'||v_clazz||'-'||v_college);
    • 异常处理:exception

      -- sqlcode:异常编号,sqlerrom:异常信息

      -- 捕获异常
      EXCEPTION
         WHEN no_data_found THEN
          dbms_output.put_line('没有数据');
         WHEN too_many_rows THEN
          dbms_output.put_line('返回太多行');
         WHEN OTHERS THEN -- 对未知异常的处理
          dbms_output.put_line(SQLCODE||'-'||SQLERRM);
    • 选择语句(在编程窗口执行):IF ELSIF

      -- 成绩大于小于60为没有通过,大于60通过
      declare
       -- Local variables here
      i integer;
      begin
       -- Test statements here
      i:=60;
       IF i<60 THEN
        dbms_output.put_line('no pass');
         ELSE
          dbms_output.put_line('pass');
           END IF;
      end;
    • 选择语句(在SQL窗口执行): case when

      SELECT score,CASE 
       WHEN score BETWEEN 0 AND 59 THEN '不及格'
        WHEN score BETWEEN 60 AND 80 THEN '普通'
         WHEN score BETWEEN 80 AND 90 THEN '良好'
           WHEN score BETWEEN 90 AND 100 THEN '优秀'
             END
             FROM t_score;
    • for循环

      declare 
       -- Local variables here
      v_score INTEGER;-- 成绩
      i integer;
      begin
       -- Test statements here
       DELETE FROM t_score;-- 测试前先删除表数据
       FOR i IN 1..10 LOOP -- 2. for循环
      v_score:=abs(mod(dbms_random.random,100)); -- 1. 随机数
         INSERT INTO t_score(NAME,score) VALUES('name'||seq1.nextval,v_score);
       END LOOP;
       COMMIT;
      dbms_output.put_line(i);
      end;
    • while循环

      -- 变量定义时为初始化为null,无法进行比较
      declare
       -- Local variables here
      i INTEGER;
      BEGIN
       IF i IS NULL THEN
        dbms_output.put_line('i is not init');
        i:=1;
         ELSE
           IF i<10 THEN
              dbms_output.put_line('i<10');
           ELSE
            dbms_output.put_line('i>=10');
       -- Test statements here
       WHILE i<10 LOOP
        i:=i+1;
        dbms_output.put_line(i);
       END LOOP;
      end;
    • loop end loop

      declare 
       -- Local variables here
      i integer;
      begin
       -- Test statements here
       /*
       for ... loop
         end loop
         while loop
           end loop
       */
       LOOP
         IF i IS NULL THEN
          i:=0;
          ELSIF i<10 THEN
            i:=i+1;
             ELSE
               EXIT; -- 退出循环
               END IF;
              dbms_output.put_line(i);
               END LOOP;
      end;

      -- 示例2
      declare
       -- Local variables here
      i integer;
      begin
       -- Test statements here
      i:=0;
       LOOP
        i:=i+1;
         EXIT WHEN i>10;
        dbms_output.put_line(i);
         END LOOP;
      end;

(八)异常、游标、存储过程、自定义函数

  1. 自定义一个异常,当i未初始化时抛出异常,处理异常

    declare 
     -- Local variables here
    i INTEGER :=0;
    myex EXCEPTION;
    BEGIN
     -- 抛出一个系统自己编号的异常
     IF i IS NULL THEN
      RAISE myex;
     END IF;
     -- 抛出一个带有编号和信息的异常,自己定义的编号范围为(-20000,-29999)
     IF i=0 THEN
      raise_application_error(-20000,'i值不能为0');
     END IF;
    EXCEPTION
       WHEN myex THEN
        dbms_output.put_line('i未初始化');
       WHEN OTHERS THEN
        dbms_output.put_line(SQLCODE||'-'||SQLERRM);
     -- Test statements here
    end;
  2. 异常不能重复抛出,但是异常可以同时捕获

    when ex1 or ex2 or ex3 then
    ...
  3. 游标:cursor

    • 定义

      游标是数据的集合,也可以说是数据集合的指针,可以从游标中获取集合中的值,一般在程序中使用,如:存储过程,函数,触发器

    • 类型:

      • 系统游标(也叫隐式游标)

      • 用户游标:包含静态游标和动态游标

    • 游标的操作:打开游标,遍历游标,关闭游标

    • 用户游标

      • 静态游标

        • 手动打开游标,关闭游标,需要写指针移动的语句

          declare 
           -- Local variables here
           -- 静态游标:后面的select语句是固定的
           CURSOR c_emp IS SELECT * FROM emp WHERE deptno=10;
           -- 定义一个变量,接收游标所指向的记录
          v_row emp%ROWTYPE;
          begin
           -- Test statements here
           -- 1.打开游标
           OPEN c_emp;
           -- 2. 遍历游标
           LOOP
             -- 游标指针的移动,取出游标所指向的记录,赋值给变量
             FETCH c_emp INTO v_row; dbms_output.put_line(v_row.empno||'-'||v_row.ename);
             -- 当遍历完成的时候,跳出循环
             EXIT WHEN c_emp%NOTFOUND;
           END LOOP;
           -- 3.关闭游标
           IF c_emp%ISOPEN THEN
             CLOSE c_emp;
           END IF;
           -- 4.异常处理
          EXCEPTION
             WHEN OTHERS THEN
              dbms_output.put_line(SQLCODE||'-'||SQLERRM);
          end;
        • 简单操作,不用打开和关闭游标

          declare 
           -- Local variables here
          i integer;
           -- 定义一个静态游标
           CURSOR c_emp IS SELECT * FROM emp WHERE deptno=10;
           -- 定义一个变量,用来循环
          v_row emp%ROWTYPE;
          begin
           -- Test statements here
           -- 使用for循环
           FOR v_row IN c_emp LOOP
            dbms_output.put_line(v_row.empno||'-'||v_row.ename);
           END LOOP;
          end;
        • 带参数的静态游标

          -- 方式一
          declare
           -- Local variables here
           -- 定义游标
           CURSOR c_emp(dno emp.deptno%TYPE) IS SELECT * FROM emp WHERE deptno=dno;
           -- 定义一个行变量接收游标指向的值
          v_row emp%ROWTYPE;
          begin
           -- Test statements here
           -- 1.打开游标
           OPEN c_emp(10);
           -- 2.遍历游标
           LOOP
             FETCH c_emp INTO v_row;
            dbms_output.put_line(v_row.empno||'-'||v_row.ename);
             -- 跳出条件
             EXIT WHEN c_emp%NOTFOUND;
           END LOOP;
           -- 3.关闭游标
           IF c_emp%ISOPEN THEN
             CLOSE c_emp;
           END IF;
          end;
          -- 方式二
          declare
           -- Local variables here
           -- 定义一个游标
           CURSOR c_emp(dno emp.deptno%TYPE) IS SELECT * FROM emp WHERE deptno=dno;
           -- 定义一个行变量,用来实现for循环
          v_row emp%ROWTYPE;
          begin
           -- Test statements here
           FOR v_row IN c_emp(10) LOOP
            dbms_output.put_line(v_row.empno||'-'||v_row.ename);
           END LOOP;
          end;
      • 动态游标

        declare 
         -- Local variables here
         -- 1.定义动态游标的类型
        TYPE dync IS REF CURSOR;
         -- 2.定义游标
        c_emp dync;
         -- 5.定义一个行变量,接收游标所指向的记录
        v_row emp%ROWTYPE;
         -- 定义一个sql语句
        v_sql VARCHAR(100);
        v_dno emp.deptno%TYPE;
        begin
         -- Test statements here
         -- 3.打开游标
         SELECT deptno INTO v_dno FROM emp WHERE empno=7369;
        v_sql :='SELECT * FROM emp WHERE deptno='||v_dno;
         OPEN c_emp FOR v_sql;
         -- 4.遍历游标
         LOOP
           FETCH c_emp INTO v_row;
          dbms_output.put_line(v_row.empno||'-'||v_row.ename);
           -- 跳出循环
           EXIT WHEN c_emp%NOTFOUND;
         END LOOP;
         -- 6.关闭游标
         IF c_emp%ISOPEN THEN
           CLOSE c_emp;
         END IF;
        end;
      • 静态游标和动态游标在定义和打开有区别,动态游标后面的select语句可以用变量来实现拼接

    • 系统游标(隐式游标)

      • 系统已经定义好的,在做DML操作时会触发,输出影响到的行数的信息

        declare 
         -- Local variables here
        i integer;
        begin
         -- Test statements here
         UPDATE emp SET sal=sal+0;
        dbms_output.put_line('影响到的行数'||SQL%ROWCOUNT);
         IF SQL%ROWCOUNT>0 THEN
          dbms_output.put_line('update success');
         ELSE
          dbms_output.put_line('update failure');
         END IF;
        end;
  4. 存储过程:procedure

    • 定义

      存储过程是一段已经编译好,并且已经有名称的程序,可以通过名称来调用他

    • 简单的存储过程

      -- 1.在sql窗口定义
      CREATE OR REPLACE PROCEDURE p1
      IS
      BEGIN
      dbms_output.put_line('hello world');
      END p1;
      -- 2.调用,可以在test窗口使用名称直接调用,也可以在sql窗口右键p1,执行
    • 带参存储过程:in表示入参,可以省略,out表示出参

      • 案例一

        CREATE OR REPLACE PROCEDURE p1(v_dno emp.deptno%TYPE)
        IS
        -- 定义了一个游标
        CURSOR c_emp IS SELECT * FROM emp WHERE deptno=v_dno;
        v_row emp%ROWTYPE;
        BEGIN
         FOR v_row IN c_emp LOOP
          dbms_output.put_line(v_row.empno||'-'||v_row.ename);
         END LOOP;
        END p1;
      • 案例二

        CREATE OR REPLACE PROCEDURE p1(v_dno IN emp.deptno%TYPE,v_count OUT NUMBER)
        IS
        BEGIN
         SELECT COUNT(*) INTO v_count FROM emp WHERE deptno=v_dno;
        END p1;
    • 存储过程处理业务逻辑,如果有返回通过出参返回

    • 拓展

      • 集群:尽量把业务或操作分开执行,就像以前一个人做事情,现在分成了多个部门,自己做好自己的事情

      • 如果把逻辑都给数据库,则数据库处理就成了瓶颈,影响系统的性能,我们会把工作交由应用服务器来处理,数据库只管数据,不管业务,给数据库松绑

  5. 自定义函数

    • 定义

      自定义函数也是一段编译好的由名称的程序,和存储过程的区别是主要是为了得到一些数据(强调的是返回的东西),存储过程强调的是做什么事情,以及过程

    • 简单的自定义函数及使用

      -- 获取某部门的员工人数
      CREATE OR REPLACE FUNCTION f1(v_dno emp.deptno%TYPE)
      -- 1. 返回类型
      RETURN NUMBER
      IS
      -- 2.定义变量
      v_count NUMBER;
      BEGIN
       -- 3.赋值
       SELECT COUNT(*) INTO v_count FROM emp WHERE deptno=v_dno;
       -- 4.返回
       RETURN v_count;
      END f1;
    • 带参的自定义函数:in入参,out出参,和存储过程一样

(九)触发器

  1. 概念

    触发器不能主动调用,只有在对相应对象操作时自动触发。

  2. 触发器分类

    • DML触发器

    • 替代触发器

    • 系统触发器

  3. DML触发器

    • 触发器的粒度

      • 语句级触发器:对sql操作只做一次触发

      • 行级触发器:对每行数据都触发

      • 示例

        insert into emp(empno) where empno in (1,2);
        -- 语句级触发器就只触发一次
        -- 行级触发器会触发两次,因为这条sql语句影响两行
    • 创建触发器

      • 语句级触发器

        create or replace trigger 触发器名称
        after/before insert or update or delete
        on 表名
        delclare
        变量声明的地方
        begin
        end;
      • 行级触发器

        create or replace trigger 触发器名称
        after/before insert or update or delete
        on 表名
        for each row
        delclare
        变量声明的地方
        begin
        end;
  4. DDL触发器

    • 当创建表,删除表,修改表时触发

    • DDL触发器的创建

      CREATE OR REPLACE TRIGGER trg_ddl
      AFTER DDL
      ON scott.schema
      DECLARE
      BEGIN
       INSERT INTO t_log(ID,log_user,log_date,log_text)
       VALUES(seq1.nextval,USER,SYSDATE,ora_sysevent||'-'||ora_dict_obj_name||'-'||ora_dict_obj_type);
      END;
  5. 替代触发器

    • 解决复杂视图不能插入数据的问题

    • 替代触发器的创建

      CREATE OR REPLACE TRIGGER trg_vemp
      INSTEAD OF INSERT
      ON v_emp
      FOR EACH ROW
      DECLARE
      BEGIN
       INSERT INTO emp(empno,sal,comm) VALUES(:new.empno,:new.sal,0);
      END;

(十)事务、锁

  • 事务的四大特点

    • 原子性:要么都做,要么都不做

    • 一致性:事务操作前和操作后是平衡的

    • 隔离性:多个事务并发对同一数据进行操作时,会有顺序,互不影响

    • 永久性:当事务提交后,数据会永久保存,断电或重启不会产生影响

  • 锁的分类

    • 从限制程序角度

      • 排他锁

      • 共享锁

    • 从产生时机角度

      • 自动锁

      • 显示锁

    • 从产生的操作角度

      • DML锁

      • DDL锁

    • 悲观锁和乐观锁

(十一)PGA、SGA、存储空间、分区表、union和union all、导入导出、SQL优化

  1. PGA

    • 程序缓存区,为了特定用户进程服务,是私有的

    • 功能

      • 排序区

      • 会话区

      • 堆栈区

      • 游标区

  2. SGA

    • 系统全局区,所有用户都能使用,是共享的,一个oracle实例,一个SGA区

    • 组成

      1. 固定区:通过这个区查找其他区的地址

      2. 重做缓冲区

      3. 块缓冲区

      4. 共享池

      5. 大池

      6. Java池

      7. 流池

  3. 存储空间

    从小到大依次为:数据块,分区,段,表空间

    • 数据块设置的大小应合理

    • 分区是一系列连续的数据块的集合

    • 数据段是分区的上层组织单位

    • 表空间中有多个段,段和文件相对应

  4. 分区表

  • 将一张表的数据存储到不同的表空间

  • 优点

    1. 增强可用性,一个分区坏了,其他分区还可以用

    2. 均衡I/O,可以把表的不同分区分配到不同的磁盘I/O来平衡I/O改善性能

    3. 提高性能,对大表的查询,增加,修改等操作可以分解到表的不同分区来并行执行,可使运行速度更快

    4. 分区对用户透明,用户感觉是同一张表

  • 分类:按范围分区,hash分区,复杂分区

  • 建立分区

    -- 1.建立3个表空间
    CREATE TABLESPACE tb1 DATAFILE 'tb1.dbf' SIZE 1m;
    CREATE TABLESPACE tb2 DATAFILE 'tb2.dbf' SIZE 1m;
    CREATE TABLESPACE tb3 DATAFILE 'tb3.dbf' SIZE 1m;
    -- 2.建立分区表,
    -- 根据范围分区
    CREATE TABLE t_area(ID NUMBER PRIMARY KEY,money NUMBER)
    PARTITION BY RANGE(money)
    (
    PARTITION p1 VALUES LESS THAN (1500) TABLESPACE tb1,
    PARTITION p2 VALUES LESS THAN (3000) TABLESPACE tb2,
    PARTITION p3 VALUES LESS THAN (MAXVALUE) TABLESPACE tb3
    );
    -- hash分区
    CREATE TABLE t_area(ID NUMBER PRIMARY KEY,money NUMBER)
    PARTITION BY HASH(money)
    (
    PARTITION p1  TABLESPACE tb1,
    PARTITION p2  TABLESPACE tb2,
    PARTITION p3  TABLESPACE tb3
    );
    -- 3.插入数据
    INSERT INTO t_area VALUES(sq.nextval,1000);-- 将插入到分区p1
    INSERT INTO t_area VALUES(sq.nextval,2000);-- 将插入到分区p2
    INSERT INTO t_area VALUES(sq.nextval,5000);-- 将插入到分区p3
    -- 4.查询数据,在相应分区查询相应的money
    SELECT * FROM t_area PARTITION(p1);-- 查询p1分区
    SELECT * FROM t_area PARTITION(p2);-- 查询p2分区
    SELECT * FROM t_area PARTITION(p3);-- 查询p3分区
    -- 查询6000工资员工的信息,在p3分区查找
    select * from t_area partition(p3) where money=6000;
    -- 内容,分区都删除
    ALTER TABLE yourTable DROP PARTITION partionName1;
    -- 只清除数据
    ALTER TABLE yourTable TRUNCATE PARTITION partionName1;
  • 为分区建立索引

    • 全局索引

      create index 索引名称 on 表名(字段) global

      partition by range (字段)
      (
       partition index_part1 values less than (60),

       partition index_part2 values less than (80),

       partition index_partmax values less than (maxvalue)
      );
    • 局部索引

      create index 索引名 on 表名 (字段1, 字段2) local;
  1. union和union all

    • union和union all的要求

      • 每条sql的列数相同

      • 每条sql的列的类型要相互匹配,char对char,number对number

    • 区别

      union结果没有重复的,union all结果重复

  2. 导入导出

    • 导出

      • pl/sql导出:tools->export

      • 命令行导出:

        exp scott/scott@orcl file="d:/1.sql"
    • 导入

      • pl/sql导入:tools->import

      • 命令行导入:

        imp scott/scott@orcl file="d:/1.sql" full=y
        -- 成功终止导入,说明导入成功
  3. SQL优化

    • 写出具体的列名,不写*,减少SQL的分析时间,不用再去数据字典中找列的信息。

    • 创建索引

    • 对索引列的过滤时,不用函数,不要隐匿转换数据类型,不用模糊匹配开头查询

    • 创建合理的表结构,可以适当对数据进行冗余,减少子查询



软件下载提取码:qwer
原文地址:https://www.cnblogs.com/ty0910/p/14354704.html