Oracle数据库

来源:互联网 发布:javascript时间格式化 编辑:程序博客网 时间:2024/05/09 05:16
oracle数据库
前言     oracle sql
第一章   Selecting Rows
第二章   Sorting & Limiting Selected Rows
第三章   Single Row Functions
第四章   Displaying Data from Multiple Tables
第五章   Group Function
第六章   Subqueries
第七章   Specifying Variables at Runtime
第八章   Overview of Data Modeling and Database Design
第九章   Creating Tables
第十章   Oracle Data Dictionary
第十一章 Manipulating Data(DML)
第十二章 Altering Tables and Constraints
第十三章 Creating Sequences
第十四章 Creating View
第十五章 Creating Indexes
第十六章 Controlling User Access
前言:
    1.一个认知
        认知什么是oracle?
            oracle:商业运用第一的关系型数据库
            实质:关系型数据库
    2.二个概念
        数据库:数据存储的仓库
        关系型数据库:数据库中保存的对象之间可以存在一定的关联关系,并非完全独立。主要反映到以后学习的主外键.
    3.三个名词
        sql:结构化的查询语句,操作oracle数据库的语言
        sqlplus:oracle软件自带的可以输入sql,且将sql执行结果显示的终端
        pl/sql:程序化的sql语句,在sql语句的基础上加入一定的逻辑操作,如if for...,使之成为一个sql块,完成一定的功能
    4.四种对象
        table:表格,由行和列组成,列又称字段,每一行内容为表格的一条完整的数据。
        view:  视图,一张表或者多张表的部分或者完整的映射,好比表格照镜子,镜子里面的虚像就是view
        除去常见的table和view两种对象以外,oracle数据库还支持如下四种对象
        sequence:序列
        index:索引,提高数据的访问效率
        synonym:同义,方便对象的操作
        program unit:程序单元,pl/sql操作的对象
    5.五种分类
        sql的五大分类:
        Data retrieval:数据查询
        select
        DML:数据操纵语言(行级操作语言):操作的是表格当中一条一条的数据
        insert update delete
        DDL:数据定义语言(表级操作语言):操作的内容为表格(对象)
        create alter drop truncate rename
        transaction control:事务控制    
        commit rollback savepoint
        DCL:数据控制语言
        grant revoke
    
        
    delete,truncate区别:
        delete:  删除表中的一条或者多条记录,该操作需要提交事务
        truncate:清空表中数据,该操作不需要提交事务

====================================================================

第一章:select语句,数据查询操作

1.使用select语句查询某张表的所有数据内容
    语法:
    select [distinct] *{col_name1,col_name2,..}
    from tb_name;
    注意:语法中出现的中括号[ ],表示该部分可有可无
    *:表示所有列,仅仅作为测试和学习使用,在企业用语中不出现,因为效率低下且可读性差
    col_name1:列名,将需要查阅的数据字段列举出来,可以查看多列值,列名之间用,进行分割即可
    s_emp :员工信息表
    s_dept:员工部门表
需求:查看s_dept表中的所有记录
    select *
    from s_dept;

    select id,name,region_id
    from s_dept;
练习:查看s_dept表中的所有记录的id和name
    select id,name
    from s_dept;


练习:查看所有员工的id,名字(last_name)和薪资(salary)
    select id,last_name,salary
    from s_emp;

2.select语句可以对指定的列的所有值进行算术运算。
    语法:
    select col_name 运算符 数字
    from tb_name;
需求:查看每个员工的员工id,名字和年薪。
    select id,last_name,salary*12
    from s_emp;
注意:select语句永远不对原始数据进行修改。
练习:查看每个员工的员工id,名字和月薪涨100以后的年薪
    select id,last_name,(salary+100)*12
    from s_emp;
3.给查询的列起别名
    语法:
    select old_column [as] new_column_name
    from tb_name;
需求:查看员工的员工id,名字和年薪,年薪列名为annual
    select id,last_name,salary*12 as annual
    from s_emp;

4.使用||可以使得多列的值或者列和特殊的字符串合并到一个列进行显示
    语法:
    select col_name||'spe_char'||col_name
    from tb_name
    'spe_char':如果一个列的值要跟特殊的字符串连接显示,使用该语法。
需求:查看员工的员工id,全名
    select id,first_name||last_name
    from s_emp;
练习:查看员工的员工id,全名和职位名称,全名和职位名称合并成一列显示,且格式为:姓 名,职位名称
    select id,first_name||' '||last_name||','||title as name
    from s_emp;

5.对null值得替换运算
    nvl()函数
    语法:
    select nvl(col_name,change_value)
    from tb_name;
需求:查看所有员工的员工id,名字和提成,如果提成为空,显示成0
    select id,last_name,nvl(commission_pct,0) commission_pct
    from s_emp;
6.使用distinct关键词,可以将显示中重复的记录只显示一条
    语法:
    select distinct col_name,col_name...
    from tb_name;

    注意1:distinct关键词只能放在select关键词后面
        如:select id,distinct title
            from s_emp;
        该语句语法错!!!!!
    注意2:如果distinct关键词后面如果出现多列,表示多列联合去重,即多列的值都相同的时候才会认为是重复的记录。
    test表:
    id    id2
    1    2
    1    3
    2    4
    3    4
    3    4
    select distinct id,id2
    from test;
    显示结果为:
    id    id2
    1    2
    1    3
    2    4
    3    4
需求:查看所有员工的职位名称和部门id,同职位同部门的只显示一次
    select distinct title,dept_id
    from s_emp;

7.sqlplus命令
   sqlplus 登录之后,可以使用buff(缓存)来存储/执行/修改要执行的sql语句
   这里的buff的特点:
      1.buff中只能存储一条sql语句(但是这条sql语句可能有很多行)
      2.每次放入新的sql语句,会把之前的覆盖掉
      3.每次执行sql语句,都会把这个sql语句放到buff里面

    l   查看缓存中的sql语句
    a   在[定位]的那一行后面追加新的内容
    i   在[定位]的那一行下面插入新的一行
    c   替换[定位]的那一行中的某些字符串
        c/老的字符串/新的字符串
    del 删除[定位]的那一行内容
    n   后面加内容可以重写这一行
    !   后面接终端命令 !clear:清屏 windows中使用$符号 例如:$cls
    /   执行缓存sql命令

    clear buffer:清空当前缓存的命令

        
    save  test.sql  buff中的sql语句保存在test.sql文件中
    get   test.sql  把test.sql中的内容在加载到buff中,但是没有运行
    start test.sql  把test.sql中的内容在加载到buff中并且执行
    @test.sql       把test.sql中的内容在加载到buff中并且执行
    edit file_name  使用系统默认编辑器去编辑文件



    spool file_name 将接下来的sql语句以及sql的运行结果保存到文件中
        sql1
        result1
        sql2
        result2
        ...
    spool off  关闭spool功能
    exit:退出
    
8.select id,last_name,first_name, salary, dept_id
  from s_emp
  Where rownum <=10;

  结果不好看,通过column使我们的显示界面好看。

    COLUMN last_name FORMAT a15;
    可以简写为:
    col last_name for a15;
    COLUMN first_name FORMAT a15;

    Column 没有改变数据表里数据,它只是改变显示。Column不是SQL命令,而是sqlplus命令。除了刚才这个作用之外,我们下面来看看它还有什么作用。

    COLUMN last_name HEADING 'Employee|Name' FORMAT A15
    . 给last_name取别名为Employee|Name , 竖杠代表换行。
    . A15表示十五个字节长,一短横杠就是一个字节长

    COLUMN salary JUSTIFY LEFT FORMAT $99,999.00
    . salary JUSTIFY LEFT : 仅仅改变列名显示为左齐
    . FORMAT $99,999.00: 控制显示格式为前面加 $ 符, “,”为分隔符, 0或9代表数字(通配符),0表示替换对齐数值,位数不足会补足,可以混合使用。

    COLUMN start_date FORMAT A8 NULL 'Not hired'
    . 如果start_date值为空的话,显示为’Not hired’;
    . Format后不能直接跟null, 要先a8或a10;
    . NULL 'Not hired'和nvl类似

    column 显示所有对列格式的设置情况
    column last_name 显示对last_name列显示设置的情况
    column last_name clear 删除对last_name列格式设置的情况
    Clear column 清除所有column的格式设置
    
    Column columName
    可以显示该列的格式设置,这里的列并不特定于某个表.

    注意:
    1234   column 99.99  -- > ###### //出错的时候不能显示,只是显示####

第二章:排序和限制查询

    1.排序:所谓排序,就是根据某个字段的值按照升序或者降序的情况将记录查询出来
        语法:
        select col_name,...
        from tb_name
        order by col_name [asc|desc],...
    注意:1.排序使用order by字句,该子句只对查询记录显示调整,并不改变查询结果,所以执行权最低,即最后执行。
    2.排序关键词:
        asc:升序(默认,默认的意思是不加关键词的时候默认为生序排序)
        desc:降序
    3.如果有多个列排序,后面的列排序的前提是前面的列排好序以后有重复(相同)的值。

    例子:
    id    id2
    1    2
    2    3
    3    4
    4    1
    4    2

    语句:
    select id,id2
    from test
    order by id,id2 desc;
    
    结果:
    id    id2
    1    2
    2    3
    3    4
    4    2
    4    1
    注意:先排第一列,如果第一列有重复的值再排第二列,以此类推
需求:查看员工的id,名字和薪资,按照薪资的降序排序显示。
    
    4.order by 后面还可以跟数字,表示使用select后面的第几个列进行排序
    例如:
    //使用last_name列进行排序
    select last_name,salary
    from s_emp
    order by 1;
    
    //使用salary列进行排序
    select last_name,salary
    from s_emp
    order by 2;

2.限制查询,即指定查询条件进行查询
    语法:
    select col_name,...
    from tb_name
    where col_name 比较操作表达式
    逻辑操作符
          col_name 比较操作表达式
    ...
    注意:
    1.限制查询条件,使用where子句
    2.条件可以多个,使用逻辑操作符和()进行条件的逻辑整合
    3.where子句的优先级别最高
    4.比较操作表达式由操作符和值组成
        常见的操作:
        1》逻辑比较操作符
        =  >  <  >=  <=
        2》不等于:三个都表示不等于的意思(经常用的是!=)
        !=   <>   ^=

需求:查看员工工资小于1000的员工id和名字
    select id,last_name,salary
    from s_emp
    where salary < 1000;

        3》sql比较操作符SQL comparison operators
              BETWEEN ... AND...
            IN(list)
            LIKE
            IS NULL

        between and:在什么范围之内 [x,y]
需求:查看员工工资在700 到 1500之间的员工id,和名字
    select id,last_name,salary
    from s_emp
    where salary between 700 and 1500;
    
    也可以在日期列上使用between and操作,但是要看当前session会话的语言环境来决定使用中文格式的日期还是英文格式的日期
    alter session set nls_language='simplified chinese';
    如果是中文的语言环境:
    查询在90年3月8号到91年2月9号之间入职的员工信息
    select id,last_name,start_date
    from s_emp
    where start_date between '08-3月-90' and '09-2月-91';
    

    alter session set nls_language=english;
    如果是英文的语言环境:
    查询在90年3月8号到91年2月9号之间入职的员工信息
    select id,last_name,start_date
    from s_emp
    where start_date between '08-MAR-90' and '09-FEB-91';


        in(list):在一个列表中
需求:查看员工号1,3,5,7,9员工的工资
    select id,last_name,salary
    from s_emp
    where id in (1,3,5,7,9);

需求:查看是在'08-3月-90'或者'09-2月-91'入职的员工信息
    select id,last_name,start_date
    from s_emp
    where start_date in ('08-3月-90','09-2月-91');

需求:查看名字为Ngao或者Smith的员工信息    
    select id,last_name,salary
    from s_emp
    where last_name in ('Ngao','Smith');


        like:模糊查询,即值不是精确的值的时候使用
        通配符,即可以代替任何内容的符号
        % :通配0到多个字符
        _ : 当且仅当通配一个字符

        转义字符:
        默认为\,可以指定 指定的时候用escape 符号指明即可,转义字符只能转义后面的一个字符
需求:查看员工名字以C字母开头的员工的id,工资。
    select id,last_name,salary
    from s_emp
    where last_name like 'C%';
练习:查看员工名字长度不小于5,且第四个字母为n的员工id和工资
     select id,last_name,salary
    from s_emp
    where last_name like '___n_%';
需求:查看员工名字中包换一个_的员工id和工资
    注意:_是一个特殊字符,所以要转义
    select id,last_name,salary
    from s_emp
    where last_name like '%\_%' escape '\';


       is null:对null值操作特定义的操作符,不能使用=
需求:查看员工提成为空的员工的id和名字
    select id,last_name,commission_pct
    from s_emp
    where commission_pct is null;

    4》逻辑操作符
    当条件有多个的时候使用
        and:且逻辑
        or: 或逻辑
        注意:and优先级比or优先级要高
        not:非逻辑
          NOT BETWEEN AND
         NOT IN
        NOT LIKE
        IS NOT NULL

需求:查看员工部门id为41且职位名称为Stock Clerk(存库管理员)的员工id和名字
    select id,last_name,dept_id,title
    from s_emp
    where dept_id = 41
    and
    title = 'Stock Clerk';
练习:查看员工部门为41 或者 44号部门 且工资大于1000的员工信息
    select id,last_name,dept_id,salary
    from s_emp
    where salary > 1000
    and
    (
    dept_id = 41
    or
    dept_id = 44
    );

    查看员工部门为41且工资大于1000 或者 44号部门的员工信息
    select id,last_name,dept_id,salary
    from s_emp
    where salary > 1000
    and
    dept_id = 41
    or
    dept_id = 44;


需求:查看员工提成不为空的员工信息
    select id,last_name,commission_pct
    from s_emp
    where commission_pct is not null;

需求:查看员工名字不是以C字母开头的员工信息。
    select id,last_name,salary
    from s_emp
    where last_name not like 'C%';

第三章:单值函数

    函数分为:
      1.单值函数
          1.字符函数
          2.日期函数
          3.转换函数
          4.数字函数
      2.分组函数(后面的章节再做学习)
    

    哑表dual
      dual是一个虚拟表,用来构成select的语法规则,oracle保证dual里面永远只有一条记录。
      例如:
      显示1+1的结果,可以看出,dual很多时候是为了构成select的标准语法
      select 1+1 from dual;

    
    字符函数
      LOWER        Converts to lowercase
      UPPER        Converts to uppercase
      INITCAP    Converts to initial capitalization
      CONCAT    Concatenates values
      SUBSTR    Returns substring
      LENGTH    Returns number of characters
      NVL        Converts a null value    

      lower 把字符转为小写
          例如:把'HELLO'转换为小写
          select lower('HELLO')
          from dual;
          
          例如:把s_emp表中的last_name列的值转换为小写
          select lower(last_name)
          from s_emp;
        
      upper 把字符转换为大写
          例如:把'world'转换为大写
          select upper('world')
          from dual;

          例如:把s_emp表中的last_name列的值转换为大写
          select upper(last_name)
          from s_emp;
          
          
          例如:查询s_emp表中名字为Ngao的人信息
          这样是查不到:
          select last_name,salary,dept_id
          from s_emp
          where last_name='NGAO';
          这样就可以查询到了:
          select last_name,salary,dept_id
          from s_emp
          where upper(last_name)='NGAO';

      initcap 把字符串首字母转换为大写
          例如:把'hELLO'转换为首字母大写,其余字母小写
          select initcap('hELLO')
          from dual;
      concat 把俩个字符串连接在一起(类似之前的||的作用)
          例如:把'hello'和'world'俩个字符串连接到一起,并且起个别名为msg
          select concat('hello','world') msg
          from dual;
          
          例如:把first_name和last_name俩个列的值连接到一起
          select concat(first_name,last_name) as name
          from s_emp;

      
      substr 截取字符串
          例如:截取'hello'字符串,从第2个字符开始(包含第二个字符),截取后面连续的3个字符
          select substr('hello',2,3)
          from dual;


      length 获得字符串长度
          例如:获得'world'字符串的长度
          select length('world')
          from dual;

          例如:获得s_emp表中last_name列的每个值的字符长度
          select length(last_name)
          from s_emp;

      nvl 替换列中为null的值
          在前面的章节已经使用过了
          select last_name,nvl(commission_pct,0)
          from s_emp;



    数字函数
      ROUND        Rounds value to specified decimal
      TRUNC        Truncates value to specified decimal
      MOD        Returns remainder of division   


      round 四舍五入
          round(arg1,arg2)
          第一个参数表示要进行四舍五入操作的数字
          第二个参数表示保留到哪一位

          例如:
          保留到小数点后面2位
          select round(45.923,2)
          from dual;

          保留到个位 (个十百千万...)
          select round(45.923,0)
          from dual;

          保留到十位 (个十百千万...)
          select round(45.923,-1)
          from dual;


      trunc 截取到某一位
          trunc(arg1,arg2)
          和round的用法一样,但是trunc只舍去不进位

          例如:
          截取到小数点后面2位
          select trunc(45.929,2)
          from dual;

          截取到个位 (个十百千万...)
          select trunc(45.923,0)
          from dual;

          截取到十位 (个十百千万...)
          select trunc(45.923,-1)
          from dual;            


      mod 取余
          mod(arg1,arg2)    
          第一个参数表示要进行取余操作的数字
          第二个参数表示参数1和谁取余
          
          例如:
          把10和3进行取余 (10除以3然后获取余数)
          select mod(10,3)
          from dual;



    日期函数
      MONTHS_BETWEEN   Number of months between two dates
      ADD_MONTHS       Add calendar months to date
      NEXT_DAY           Next day of the date specified
      LAST_DAY           Last day of the month
      ROUND               Round to date at midnight
      TRUNC               Remove time portion  from date


         sysdate关键字
        表示系统的当前时间    
        例如:
        显示时间:当前时间
        select sysdate from dual;

        注意:sysdate进行加减操作的时候,单位是天
        例如:
        显示时间:明天的这个时候
        select sysdate+1 from dual;

        例如:
        显示时间:昨天的这个时候
        select sysdate-1 from dual;
        
        例如:
        显示时间:1小时之后的这个日期
        select sysdate+1/24 from dual;

        
      months_between 俩个日期之间相差多少个月(单位是月)
        例如:
        30天之后和现在相差多少个月
        select months_between(sysdate+30,sysdate)
        from dual;


      add_months  返回一个日期数据:表示一个时间点,往后推x月的日期
        例如:
        '01-2月-2016'往后推2个月
        select add_months('01-2月-2016',2)
        from dual;    
        
        例如:
        当前时间往后推4个月
        select add_months(sysdate,4)
        from dual;

        注意:这个数字也可以是负数,表示往前推x月

      next_day 返回一个日期数据:表示一个时间点后的下一个星期几在哪一天
        例如:
        离当前时间最近的下一个星期5是哪一个天
        select next_day(sysdate,'星期五')
        from dual;
        注意:
        如果要使用'FRIDAY',那么需要把当前会话的语言环境修改为英文


      last_day 返回一个日期数据:表示一个日期所在月份的最后一天
        例如:
        当前日期所在月份的最后一天(月底)
        select last_day(sysdate)
        from dual;


      round  对日期进四舍五入,返回操作后的日期数据
        例如:
        把当前日期四舍五入到月
        select round(sysdate,'MONTH')
        from dual;
        测试:15号16号分别是舍弃还是进位
        
        把当前日期四舍五入到年
        select round(sysdate,'YEAR')
        from dual;
        
        //这个写法是错误的
        //数字函数也有一个round
        //俩个ronnd函数有冲突
        //所以这里不能使用默认的日期格式
        select round('01-2月-2016','MONTH')
        from dual;

      trunc  对日期进行截取 和round类似,但是只舍弃不进位




    类型转换函数
      TO_CHAR converts a number or date string to a character string.
      TO_NUMBER converts a character string containing digits to a number.
    TO_DATE converts a character string of a date to a date value.
      

      to_char 把日期转换为字符

        例如:
        把当前日期按照指定格式转换为字符串
        select to_char(sysdate,'yyyy')
        from dual;
        
          日期格式:
          yyyy:四位数的年份
          rrrr:四位数的年份
          yy:两位数的年份
          rr:两位数的年份
          mm:两位数的月份(数字)
          D:一周的星期几
          DD:一月的第几天
          DDD :一年的第几天
          YEAR:英文的年份
          MONTH:英文全称的月份
          mon:英文简写的月份
          ddsp:英文的第几天(一个月的)
          ddspth:英文序列数的第几天(一个月的)
          DAY:全英文的星期
          DY:简写的英文星期
          hh:小时
          mi:分钟
          ss:秒

        例如:
        测试常见的一些日期数据转换为字符串的格式
        select to_char(sysdate,'yyyy MM D DD DDD YEAR MONTH ddsp ddspth DAY DY') from dual;

        select to_char(sysdate,'dd-mm-yy')
        from dual;

        select to_char(sysdate,'yy-mm-dd')
        from dual;

        select to_char(sysdate,'dd-mm-yy HH24:MI:SS AM')
        from dual;


      千年虫:
        在早期的计算机的程序中规定了的年份仅用两位数来表示。也就是说,假如是1971年,在计算机里就会被表示为71,但是到了2000年的时候这个情况就出现了问题,计算机就会将其年份表示为00。这样的话计算机内部对年份的计算就会出现问题。这个事情当时被称为千年虫
    
        数据库中表示日期中年份的有俩种: yy和rr
        之前一直使用的时候yy格式,后来才有的rr格式
        yy表示使用一个俩位数表示当前年份:
        1990 ---yy数据库格式---> 90
        1968 ---yy数据库格式---> 68
        1979 ---yy数据库格式---> 79
        
        rr格式表示: 另外参照图片:rr日期格式规则.png
        如果日期中的年份采用的格式为rr,并且只提供了最后2位年份,那么年份中的前两位数字就由两部分共同确定:提供年份的两位数字(指定年),数据库服务器上当前日期中年份的后2位数字(当年)。确定指定年所在世纪的规则如下:
        规则1 如果指定年在00~49之间,并且当前年份在00~49之间,那么指定年的世纪就与当前年份的世纪相同。因此,指定年的前两位数字就等于当前年份的前两位数字。例如,如果指定年为15,而当前年份为2007,那么指定年就是2015。
        规则2 如果指定年在50~99之间,并且当前年份在00~49之间,那么指定年的世纪就等于当前年份的世纪减去1。因此,指定年的前两位数字等于当前年份的前两位数字减去1。例如,如果指定年为75,而当前年份为2007,那么指定年就是1975。
        规则3 如果指定年在00~49之间,并且当前年份在50~99之间,那么指定年的世纪就等于当前年份的世纪加上1。因此,指定年的前两位数字等于当前年份的前两位数字加上1。例如,如果指定年为15,而当前年份为2075,那么指定年就是2115。
        规则4 如果指定年在50~99之间,并且当前年份在50~99之间,那么指定年的世纪就与当前年份的世纪相同。因此,指定年的前两位数字就等于当前年份的前两位数字。例如,如果指定年为55,而当前年份为2075,那么指定年就是2055。

        注意:rr格式并没有完全的解决俩位数年份保存的问题,思考里面还有哪些问题存在。



      to_char 把数字转换为字符
        例如:
        select to_char(salary,'$999,999.00')
        from s_emp;

        fm表示去除结果显示中的开始的空格
        select to_char(salary,'fm$999,999.00')
        from s_emp;

        L表示系统本地的货币符号
        select to_char(salary,'fmL999,999.00')
        from s_emp;
        


      to_number 把字符转换为数字
        例如:
        select to_number('1000')
        from dual;
        
        //这个写法是错的 abc不能转换为数字
        select to_number('abc')
        from dual;

        

      to_date 把字符转换为日期
        例如:
        select to_date('10-12-2016','dd-mm-yyyy')
        from dual;

        select to_date('25-5月-95','dd-month-yy')
        from dual;

        select to_date('95/5月/25','yy/month/dd')
        from dual;

        //session语言环境设置为英文下面可以运行
        select to_date('25-MAY-95','dd-MONTH-yy')
        from dual;

        

    oracle数据库中表示一个日期数据的几种方式
      1.使用sysdate
      2.使用oracle默认的日期格式 例如:'25-MAY-95'
      3.使用日期函数ADD_MONTHS/NEXT_DAY/LAST_DAY/ROUND/TRUNC
      4.使用转换函数to_date


    函数之间的嵌套
      格式:F3(F2(F1(arg0,arg1),arg2),arg3)
      例如:
      先把'hello'和'world'连接起来,再转换为字母大写然后再从第4个字符开始,连着截取4个字符
      select substr(upper(concat('hello','world')),4,4)
      from dual;

第四章:多表查询


    多表查询,又称表联合查询,即一条sql语句涉及到的表有多张,数据通过特定的连接进行联合显示.


    笛卡尔积
        在数学中,两个集合X和Y的笛卡尓积(Cartesian product),又称直积,表示为X × Y.
        假设集合A={a, b},集合B={0, 1, 2},则两个集合的笛卡尔积为{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}。
        在数据库中,如果直接查询俩张表,那么其查询结果就会产生笛卡尔积
        例如:
        select *
        from s_emp,s_dept;
        
    
    连接查询
        为了在多表查询中避免笛卡尔积的产生,我们可以使用连接查询来解决这个问题.
        连接查询分为:
            1.等值连接
            2.不等值连接
            3.外连接
                左外连接
                右外连接
                全连接
            4.自连接
    
    等值连接
        利用一张表中某列的值和另一张表中某列的值相等的关系,把俩张表连接起来。
        例如:查询员工的名字、部门编号、部门名字
        select last_name,dept_id,name
        from s_emp,s_dept
        where s_emp.dept_id=s_dept.id;

        为了表述的更加清楚,可以给每张表起别名
        select se.last_name,se.dept_id,sd.id,sd.name
        from s_emp se,s_dept sd
        where se.dept_id=sd.id;


    不等值连接
        假设数据库中还有一张工资等级表:salgrade
        工资等级表salgrade:
            gradeName列表示等级名称
            losal     列表示这个级别的最低工资数
            hisal    列表示这个级别的最高工资数

        表中的数据类似于下面内容:
        id  salgrade    losal hisal
        1  初级程序员   2000  4000
        2  中级程序员   4000  6000
        
        例如:
        查询出员工的名字、职位、工资、工资等级名称
        SELECT  e.last_name, e.title, e.salray, s.gradeName
        FROM    s_emp e, salgrade s
        WHERE   e.salray BETWEEN s.losal AND s.hisal


    外连接
        外连接分为:左外连接 右外连接 全连接
        先分别在俩s_emp和s_dept表中插入新的数据
        特点:新员工tom不在任何部门,新增部门st下面没有任何员工
        insert into s_emp(id,last_name) values(26,'tom');
        insert into s_dept(id,name) values(60,'st');
        commit;

        下面条sql语句可以把上面插入的数据给删除掉
        delete from s_emp where id=26;
        delete from s_dept where id=60;
        commit;
        
        这个时候再使用等值连接的话,查询出来的数据就会少,因为新增的员工tom和部门表中的数据连接不上,当然新增的部门st也和员工表中的数据连接不上.那么这俩条数据都是在等值连接中查询不出来.


    左外连接
        例如:
        查询所有员工 以及对应的部门的名字,没有部门的员工也要显示出来
        select last_name,dept_id,name
        from s_emp,s_dept
        where s_emp.dept_id=s_dept.id(+);
        
        或者 俩者是等价的

        select last_name,dept_id,name
        from s_emp left outer join s_dept
        on s_emp.dept_id=s_dept.id;
        
        注意:outer可以省去不写

    
    右外连接
        例如:
        查询所有员工 以及对应的部门的名字,没有任何员工的部门也要显示出来
        select last_name,dept_id,name
        from s_emp,s_dept
        where s_emp.dept_id(+)=s_dept.id;

        select last_name,dept_id,name
        from s_emp right outer join s_dept
        on s_emp.dept_id=s_dept.id;

        注意:outer可以省去不写

    
    全连接
        例如:
        查询所有员工 以及对应的部门的名字,没有任何员工的部门也要显示出来,没有部门的员工也要显示出来
        select last_name,dept_id,name
        from s_emp full outer join s_dept
        on s_emp.dept_id=s_dept.id;

        注意:outer可以省去不写

    
    自连接
        一张表,自己和自己连接
        例如:
        查询每个员工的名字以及员工对应的管理者的名字
        select s1.last_name,s2.last_name manager_name
        from s_emp s1,s_emp s2
        where s1.manager_id = s2.id;



    对查询结果集的操作
        如果有俩条sql语句,每一条sql都可以查询出一个结果,这个被称之为结果集。那么我们可以使用下面的关键字对俩个结果集进行操作
        union        获得俩个结果集的并集
        union all    把俩个结果集 合在一起显示出来    
        minus        第一个结果集除去第二个结果集和它相同的部分
        intersect    获得俩个结果集的交集

        注意:前提条件 俩个结果集中【查询的列】要完全一致

    union  获得俩个结果集的并集
        例如:
        select last_name,dept_id,name
        from s_emp,s_dept
        where s_emp.dept_id=s_dept.id(+)
        union
        select last_name,dept_id,name
        from s_emp,s_dept
        where s_emp.dept_id(+)=s_dept.id;

    union all  把俩个结果集 合在一起显示出来    
        例如:
        select last_name,dept_id,name
        from s_emp,s_dept
        where s_emp.dept_id=s_dept.id(+)
        union all
        select last_name,dept_id,name
        from s_emp,s_dept
        where s_emp.dept_id(+)=s_dept.id;

    minus  第一个结果集除去第二个结果集和它相同的部分
        例如:
        select last_name,dept_id,name
        from s_emp,s_dept
        where s_emp.dept_id=s_dept.id(+)
        minus
        select last_name,dept_id,name
        from s_emp,s_dept
        where s_emp.dept_id(+)=s_dept.id;
        
        对比俩种情况的结果

        select last_name,dept_id,name
        from s_emp,s_dept
        where s_emp.dept_id(+)=s_dept.id
        minus
        select last_name,dept_id,name
        from s_emp,s_dept
        where s_emp.dept_id=s_dept.id(+);



    intersect  求俩个结果集的交集
        select last_name,dept_id,name
        from s_emp,s_dept
        where s_emp.dept_id=s_dept.id(+)
        intersect
        select last_name,dept_id,name
        from s_emp,s_dept
        where s_emp.dept_id(+)=s_dept.id;

    

    oracle中的伪列 rownum
        伪列rownum,就像表中的列一样,但是在表中并不存储。伪列只能查询,不能进行增删改操作。它会根据返回的结果为每一条数据生成一个序列化的数字.rownum是oracle才有的伪列

        rownum 所能作的操作:
        
        rownum 只能等于1  如果让其等于其他数 则查不到数据
        例如:
        select last_name
        from s_emp
        where rownum=1;

        rownum 大于0      如果让其大于其他数 则查不到数据
        例如:
        select last_name
        from s_emp
        where rownum>0
        
        rownum 可以小于任何数
        例如:
        select last_name
        from s_emp
        where rownum<7

第五章:组函数

    
    group by 在查询表中数据的时候进行分组的关键字
        思考:为什么要对数据进行分组
    having   分组之后的进行进一步数据筛选的关键字
        having和where的功能类似

    组函数(分组函数),是指将数据按照某列的值进行分组后,然后使用组函数分别对每个分好的小组中的数据进行处理。所以组函数一般要结合着分组关键字group来使用

    组函数:
        avg       求平均值
        count     计算有多少条数据
        max       最大值
        min       最小值
        sum       求和

        stddev    标准差
        variance  方差
    
    
    sql语句的各部分构成
        select   ....
        from     ....
        where     ....
        group by ...
        having     ...
        order by ....
        
        注:除了select和from之外其他的都不是必须的。

        假如select..from..后面的语句都出现了,那么他们的执行顺序为:
        where-->group by分组-->执行组函数-->having筛选->order by


        组函数出现的位置:
            1.select后面
            2.having后面
            3.order by后面
            4.where后面一定【不能】出现组函数

            注意:如果select/having语句后面出现了组函数,那么select/having后面没有被组函数修饰的列,就必须出现在group by 后面


        where和having对比:
           1.where和having都是做条件筛选的
           2.where执行的时间比having要早
           3.where后面不能出现组函数
           4.having后面可以出现组函数
           5.where语句要紧跟from后面
           6.having语句要紧跟group by后面

        group by和having的关系:
           1.group by可以单独存在,后面可以不出现having语句
           2.having不能单独存在,有需要的话,必须出现在group by后面

        order by语句
           1.如果sql语句中需要排序,那么就一定要写在sql语句的最后面
           2.order by后也可以出现组函数


    使用组函数:不结合group分组使用
        注:如果不使用group分组的话,那么默认当前查询到的所有数据是一组
        例如:
        查询s_emp表中所有员工的平均工资
        select avg(salary)
        from s_emp;

        查询s_emp表中共有多少条数据
        select count(*)
        from s_emp;

        查询s_emp表中所有员工中的最大工资
        select max(salary)
        from s_emp;

        查询s_emp表中所有员工中的最小工资
        select min(salary)
        from s_emp;

        查询s_emp表中所有员工的工资总和
        select sum(salary)
        from s_emp;

        查询s_emp表中所有员工的工资的标准差
        select stddev(salary)
        from s_emp;

        查询s_emp表中所有员工的工资的方差
        select variance(salary)
        from s_emp;


    使用组函数:结合group分组使用
        例如:
        查询s_emp表中每个部门的平均工资
        select dept_id,avg(salary)
        from s_emp
        group by dept_id;
    
        查询s_emp表中每个部门员工的最高工资
        select dept_id,max(salary)
        from s_emp
        group by dept_id;

        查询s_emp表中每个部门员工的工资总和
        select dept_id,sum(salary)
        from s_emp
        group by dept_id;

        查询s_emp表中每个部门员工的人数
        select dept_id,count(*)
        from s_emp
        group by dept_id;

        
        //分组之后使用各种组函数
        select dept_id,count(*),min(salary),max(salary),sum(salary),avg(salary)
        from s_emp
        group by dept_id;


    使用组函数:结合group分组以及having筛选使用
        例如:
        查询s_emp表中部门的平均工资大于等于1400的部门
        select dept_id,avg(salary)
        from s_emp
        group by dept_id
        having avg(salary)>=1400;
        
        思考:上面的sql语句修改为如下,是否可以?
        (不能)
        select dept_id,avg(salary)
        from s_emp
        where avg(salary)>=1400
        group by dept_id;

        
        查询s_emp表中部门的总工资大于等于4000的部门
        select dept_id,sum(salary)
        from s_emp
        group by dept_id
        having sum(salary)>=4000;



    使用组函数:其他实例
        例如:
        select s1.dept_id,avg(salary),s2.name
        from s_emp s1, s_dept s2
        where s1.dept_id=s2.id
        group by s1.dept_id, s2.name
        having avg(salary)>=1400
        order by 1;
        查询s_emp表中部门的平均工资大于等于1400的部门,并且显示出这些部门的名字,同时按照部门编号进行排序
        第一步:查询出基本需求
        select dept_id,avg(salary)
        from s_emp
        group by dept_id
        having avg(salary)>=1400
        order by dept_id;

        第二步:加入多表查询,并且分别给表起别名
        select se.dept_id,avg(se.salary)
        from s_emp se,s_dept sd
        group by se.dept_id
        having avg(se.salary)>=1400
        order by se.dept_id;

        第三步:查询出s_dept表中的部门名称,并且进行等值连接
        select se.dept_id,avg(se.salary),sd.name
        from s_emp se,s_dept sd
        where se.dept_id = sd.id
        group by se.dept_id
        having avg(se.salary)>=1400;
        order by se.dept_id;

        第四步:select语句后出现了组函数,那么没有被组函数修饰的列放到group by分组后面
        select se.dept_id,avg(se.salary),sd.name
        from s_emp se,s_dept sd
        where se.dept_id = sd.id
        group by se.dept_id,sd.name
        having avg(se.salary)>=1400
        order by se.dept_id;
        
        思考:是否可以把where后的条件筛选 转移 到having语句后面?

    
        查询s_emp表中最大的工资数,并且显示出这个最大工资的员工的名字
        第一步:查出最大工资数
        select max(salary)
        from s_emp;
        
        第二步:加上last_name的显示
        select last_name,max(salary)
        from s_emp;

        第三步:select后面出现组函数,没有被组函数修饰的列放到group by后面,但是发现查询结果并不是想要结果
        select last_name,max(salary)
        from s_emp
        group by last_name;
        
        第四步:修改为多表查询(起别名),从s1表中查询出最大的工资数是多少,然后再和s2表连接起来,选出s2表中这个最大工资数的员工名字
        select s2.last_name,max(s1.salary)
        from s_emp s1,s_emp s2
        where s2.salary = max(s1.salary)
        group by s2.last_name;
        
        第五步:where后面不能出现组函数,所以改为having
        select s2.last_name,max(s1.salary)
        from s_emp s1,s_emp s2
        group by s2.last_name,s2.salary
        having s2.salary = max(s1.salary);

        
        练习:
        查询s_emp表每个部门的最大工资数,并且显示出这个最大工资的员工名字以及该部门的名字和该部门所属区域,并且使用部门编号进行排序
       

第六章:子查询(嵌套查询)

    子查询,即一个select语句中嵌套了另外的一个或者多个select语句

    例如:
    查询工资比Simth工资高的员工信息
        第一步:查询Smith的工资数
        select salary
        from s_emp
        where last_name='Smith';    
        结果:
            SALARY
        ----------
               940

        第二步:查询工资比940高的员工信息
        select last_name,salary
        from s_emp
        where salary>940;

        第三步:把第二步中的数字940替换成第一步中的sql语句即可(注意格式)
        select last_name,salary
        from s_emp
        where salary>(
            select salary
            from s_emp
            where last_name='Smith'
        );

    
    例如:
    查询所有部门的平均工资
    select dept_id,avg(salary)
    from s_emp
    group by dept_id;
    
    结果:
       DEPT_ID AVG(SALARY)
    ---------- -----------
            42  1081.66667
            43         900
            34        1160
            44        1050
            31        1400
            32        1490
            35        1450
            50        2025
            41      1247.5
            45        1089
            33        1515

       DEPT_ID AVG(SALARY)
    ---------- -----------
            10        1450


    查询平均工资比1247.5高的部门编号
    select dept_id
    from s_emp
    group by dept_id
    having avg(salary)>1247.5;
    
    结果:
       DEPT_ID
    ----------
            31
            32
            35
            50
            33
            10


    查询平均工资比1247.5高的部门中员工信息
    select last_name,salary,dept_id
    from s_emp
    where dept_id in(10,31,32,33,35,50);

    等价于

    select last_name,salary,dept_id
    from s_emp
    where dept_id in(
        select dept_id
        from s_emp
        group by dept_id
        having avg(salary)>1247.5
    );



    查询平均工资比 41号部门的平均工资 高 的部门中员工的信息
    select avg(salary)
    from s_emp
    where dept_id=41;
    
    结果:
    AVG(SALARY)
    -----------
         1247.5

    所以这个sql语句和1247.5是等价的,那么就可以将上面sql语句中的1247.5给替换了
    select last_name,salary,dept_id
    from s_emp
    where dept_id in(
        select dept_id
        from s_emp
        group by dept_id
        having avg(salary)>1247.5
    );
    替换后为:
    select last_name,salary,dept_id
    from s_emp
    where dept_id in(
        select dept_id
        from s_emp
        group by dept_id
        having avg(salary)>(
            select avg(salary)
            from s_emp
            where dept_id=41
        )
    )
    group by dept_id;
------------------------------------------read on -------------------
    练习:
    注意:(可以把子查询的结果作为一张表来使用)
    查询平均工资比 41号部门的平均工资 高的部门中员工的信息,并且显示出当前部门的平均工资
    select s2.id,s2.last_name,s2.salary,s1.avg,s1.dept_id
    from
    (select dept_id,avg(salary) as avg
    from s_emp
    group by dept_id
    having dept_id in(
    select dept_id
    from s_emp
    group by dept_id
    having avg(salary) >(select avg(salary) from s_emp
            where dept_id=41))
    ) s1,
    (select id,last_name,salary,dept_id
    from s_emp
    where dept_id in(
    select dept_id
    from s_emp
    group by dept_id
    having avg(salary) >(select avg(salary) from s_emp
            where dept_id=41))
    )s2
    where s1.dept_id=s2.dept_id;
    
    查询平均工资比 41号部门的平均工资 高的部门中员工的信息,并且显示出当前部门的平均工资,同时显示出部门的名字
    


    查询员工信息,这些员工的工资要比自己所在部门的平均工资高

    查询员工信息,这些员工的工资要比自己所在部门的平均工资高,同时显示部门的名称以及所在地区



    查询工资比 Ngao所在部门平均工资 要高的员工信息,同时这个员工所在部门的平均工资 也要 比Ngao所在部门的平均工资要高

    查询工资比 Ngao所在部门平均工资 要高的员工信息,同时这个员工所在部门的平均工资 也要 比Ngao所在部门的平均工资要高,显示当前部门的平均工资

    查询工资比 Ngao所在部门平均工资 要高的员工信息,同时这个员工所在部门的平均工资 也要 比Ngao所在部门的平均工资要高,显示当前部门的平均工资以及部门的名字和所在地区

第七章:运行时参数

    sql语句中的值,我们可以使用一个参数来代替,然后每次运行的时候都可以重新输入这个值
    
    例如:
    select last_name,salary,dept_id
    from s_emp
    where id=&id;

    select last_name,salary,dept_id
    from s_emp
    where last_name=&name;
    
    select last_name,salary,dept_id
    from s_emp
    where last_name='&name';

    select last_name,salary,dept_id
    from s_emp
    where
    salary>&a
    and
    salary<&b;

    select last_name,salary,dept_id
    from s_emp
    where &con;

    select last_name,salary,dept_id
    from s_emp
    &con;

    注意:&变量名 表示使用这个oracle定义的变量,如果这个变量之前没有定义过,那么这个时候会让你重写输入这个变量的值.如果之前有定义过,那么就是要之前定义过的值
    
    define undefine accept prompt命令
    例如:
    命令def可以定义一个变量
    定义变量:         def A=s_emp
    查看定义的变量:  def
    取消定义的变量:  undef A

    然后变量A之前定义过,那么这里会之前替换为之前定义的值
    select id,last_name,salary
    from &A;

    accept命令也可以定义一个变量,而且变量的值需要用户再次输入
    例如:
    accept A
    回车之前需要用户再次输入变量A的值
    之后可以使用def命令来查看刚刚定义的A变量

    prompt可以在用户输入的时候显示一个提示信息:
    例如:
    accept name prompt '请输入name变量的值: '

    hide可以隐藏用户的输入内容不被看见
    例如:
    accept name prompt '请输入name变量的值: ' hide


    注意:这些定义的都是临时变量,sqlplus退出后重新登录进来就没有了



第八章:数据建模和数据库设计
    
    软件开发的步骤可大致分为:
        1.需求分析
        2.系统设计
        3.编码实现
        4.系统测试
        5.运行维护
    
    系统设计中一个重要的环节就是数据库设计

    数据库设计的时候需要先进行数据建模(实体关系图 E-R图)
    
    数据建模的依据就是前期所做的需求分析

    数据建模
        参照179页的图形:
        1.Model of system in client's mind
        2.Entity model of client's model
        3.Table model of entity model
        4.Tables on disk
    
    实体-关系图
        实体-关系图(Entity Relationship Diagram),也称为E-R图,提供了表示实体、属性和关系的方法,用来描述现实世界的概念模型。

        构成E-R图的基本要素是实体、属性和关系

        实体(Entity):实体用来表示具有相同特征和性质的事物(类似于java的类),实体由实体名和实体属性来表示。

        属性(Attribute):实体所具有的某一特性,一个实体可以有若干个属性

        关系(Relationship):实体彼此之间相互连接的方式称为关系。一般可分为以下 3 种类型:
            一对一关系 (1 ∶ 1)
            一对多关系 (1 ∶ N)
            多对多关系 (M ∶ N)
    

    may-be 和 must-be
        在实体与实体之间的关系中,都会存在着may-be和must-be这俩种情况,例如:
        系统中有顾客和订单俩个实体(1:N关系),一个顾客对应多个订单,一个订单对应一个顾客,而且一个顾客可以(may be)没有订单和他对应,一个订单一定(must be)会有顾客和它对应.


    ER图中符号的表示
        1) # : 唯一, 以后可能表示为主键
        2) * : 非空
        3) o : 可有可无
        4) 虚线: may be  顾客这边虚线,顾客可能没有订单
        5) 实线: must be 订单这边实线,订单一定是属于某个客户。
        6) 竖杠(|): 代表要强制在(|)一方建立一个联合主键,将对方ID拿过来做联合主键
        7) 伞状图标代表多的一方,不是伞状图标则代表一的一方


    数据库设计
        数据建模完成之后,可以把ER图转换成数据中的表
            1.实体的名字转换为表的名字
            2.实体的属性转换为表中的列
            3.具有唯一特点的属性设置为表中的主键
            4.根据实体之间的关系设置为表中某列为外键列(主外键关联)
            注意:第四步主要是:实体关系--->表关系

        设计关系数据库时,遵从不同的规范要求,才能设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小。

        目前关系数据库有六种范式:
        第一范式(1NF)
        第二范式(2NF)
        第三范式(3NF)
        巴斯-科德范式(BCNF)
        第四范式(4NF)
        第五范式(5NF,又称完美范式)

        注:满足最低要求的范式是第一范式(1NF)。在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF),其余范式以次类推。一般说来,数据库只需满足第三范式(3NF)就行了
            
    第一范式:
        一个表中,每个列里面的值是不能再分割的.
        例如:我们设计的表中有一个列是:爱好
        这个列的值可能会是这样:足球篮球乒乓球
        但是这值是可以再分割的:足球、篮球、乒乓球
        所以这种设计是不满足第一范式

    第二范式:
        第二范式是在满足第一范式的基础上
        表中的非主键列都必须依赖于主键列
        例如:
        订单表: 订单编号 是主键
        订单编号  订单名称   订单日期  订单中产品的生产地
        这几个非主键列中,产品生产地是不依赖于订单编号的,所以这种设计是不满足第二范式

    第三范式:
        第三范式是在满足第二范式的基础上
        表中的非主键列都必须直接依赖于主键列,而不能间接的依赖.
        (不能产生依赖传递)
        例如:
        订单表:   订单编号 是主键
        订单编号  订单名称  顾客编号  顾客姓名

        顾客编号依赖于订单编号,顾客姓名依赖于顾客编号,从而顾客姓名间接的依赖于订单编号,那么这里产生了依赖传递,所以这个设计是不满足第三范式的

    

    了解主键和外键
        主键:
        1.能做主键的列必要满足非空唯一的特点
        2.只要满足非空唯一的任何列都可以做主键
        3.可以让表中一个有意义的列做主键,比如说学号,它既表示学生学号又作为表中的主键,因为这个列满足非空唯一的条件
        4.也可以找一个没有意义的列做主键,就是用来唯一标识一行记录的
        5.我们可以让多个列联合在一起做表中的主键,那么它就是联合主键,要求这几个列的值联合在一起是非空唯一的    

        外键:
        1.表中的某一个列声明为外键列,一般这个外键列的值都会引用于另外一张表的主键列的值(有唯一约束的列就可以,不一定非要引用主键列)
        2.另外一张表的主键列中出现过的值都可以在外键列中使用,没有出现过的值,都不能使用
        3.外键列值也可以为空的,提前是这个外键列在表中不做主键,因为我们也可以把表中的外键列当做主键来使用(只有满足非空唯一的要求就可以)
        4.如果把B表中的联合主键的值引用到A表中做外键,因为是俩个列在B表中做联合主键,那么A表引用过来的时候也要把俩个列的值都引用过来,那么它们在A表中就会作为一个联合外键出现




第九章:建表

    建表的格式
        create table 表名(
            列名1 数据类型 列级约束,
            列名2 数据类型 列级约束,
            列名3 数据类型 列级约束,
            列名4 数据类型 列级约束
        );

        create table 表名(
            列名1 数据类型 列级约束,
            列名2 数据类型 列级约束,
            列名3 数据类型 列级约束,
            列名4 数据类型 列级约束,
            表级约束1,
            表级约束2
        );
    
    根据以上格式,可以看出,建表过程中,需要以下几种东西:
        1.关键字
        2.表名
        3.列名
        4.数据类型
        5.约束
        6.固定格式
    其中,约束分为列级约束(因为是跟在列的声明后面写的)和表级约束(因为是在全部列声明完之后写的),列级约束和表级约束都是对列中的值进行约束的,例如:列的值不能为空,列的值必须是唯一的等等
    注:列级约束也称为行级约束

    同时,列级约束和表级约束都是可选的,也就是都可以写也可以不写。例如:
        create table 表名(
            列名1 数据类型,
            列名2 数据类型,
            列名3 数据类型,
            列名4 数据类型
        );



    表名的要求:
        1.必须是字母开头
        2.必须是1-30个字符之间的长度
        3.表名中只能出现A–Z, a–z, 0–9, _, $, #
        4.不能和数据库中已有对象的名字重复
        5.不能是数据库中的关键字


    列的常用数据类型
        1.char
        2.varchar
        3.varchar2
        4.number
        5.date
        其他类型 BLOB CLOB
        BLOB和CLOB都是大字段类型,BLOB是按二进制来存储的,而CLOB是可以直接存储文字的
    
    char varchar varchar2的区别及特点
        1.CHAR的长度是固定的,而VARCHAR2的长度是可以变化的
        2.CHAR的效率比VARCHAR2的效率稍高。
        3.VARCHAR是数据库标准的字符类型
        4. VARCHAR2是Oracle自己开发了一个数据类型VARCHAR2
        5. VARCHAR2将数据库中varchar列可以存储空字符串的特性改为存储NULL值。
        6.Oracle建议使用VARCHAR2而不是VARCHAR



    列的约束
        列的约束就是对这个列中的值的要求
        1.主键约束  PRIMARY KEY  primary key
        2.外键约束  FOREIGN KEY  foreign key
        3.唯一约束  UNIQUE       unique
        4.非空约束  NOT NULL     not null
        5.check约束 CHECK         check

        列级约束/行级约束:在列的后面直接加上的约束
        create table 表名(
            列名1 数据类型 列级约束,
            列名2 数据类型 列级约束,
            列名3 数据类型 列级约束,
            列名4 数据类型 列级约束
        );

        表级约束:在所有列声明以后加的约束
        create table 表名(
            列名1 数据类型 列级约束,
            列名2 数据类型 列级约束,
            列名3 数据类型 列级约束,
            列名4 数据类型 列级约束,
            表级约束1,
            表级约束2
        );


    建表实例
        例如1:
        //普通的建表例子
        create table student(
            id number primary key,
            name varchar2(200) not null,
            age number,
            birthday date
        );

        drop table student;

        
        例如2:
        //使用四种列级约束 主键约束 非空约束 唯一约束 check约束
        create table student(
            id number primary key,
            name varchar2(100) not null,
            email varchar2(100) unique,
            gender char(1) check(gender in('f','m')),
            age number,
            birthday date
        );
        
        drop table student;


        例如3:
        //使用列级约束 声明 外键约束
        create table t_customer(
            id number primary key,
            name varchar2(200) not null
        );
        
        create table t_order(
            id number primary key,
            content varchar2(200) not null,
            customer_id number references t_customer(id)
        );
        
        drop table t_customer;
        drop table t_order;

        注意:订单表中的外键列customer_id的值,是引用自顾客表t_customer中的主键列id的值
        1.这时候直接删除顾客表是不行的,因为t_customer的主键列的值被别的表给引用了.
        2.我们可以先删除订单表t_order,然后再删除t_customer就可以了
        3.如果非要想直接删除到顾客表t_customer,就需要使用下面的语句:
            drop table t_customer cascade constraints;
        4.该语句表示,删除t_customer表的同时,也级联删除与表相关的约束,外键约束没有了,这个表自然可以被删除掉
        5.cascade是级联的意思



        例如4:
        //使用表级约束
        create table student(
            id number,
            name varchar2(20) not null,
            age number,
            email varchar2(100),
            gender char,
            primary key(id),
            unique(email),
            check(gender in('f','m'))
        );
        
        drop table student;

        注:非空约束(not null)不能声明成表级约束



        例如5:
        //使用表级约束 声明 外键约束
        create table t_customer(
            id number primary key,
            name varchar2(200) not null
        );
        
        create table t_order(
            id number primary key,
            content varchar2(200) not null,
            customer_id number,
            foreign key(customer_id) references t_customer(id)
        );
        
        drop table t_order;
        drop table t_customer;

        
        例如6:
        //使用表级约束 声明 联合唯一约束
        create table student(
            id number primary key,
            class varchar2(50) not null,
            name varchar2(50) not null,
            unique(class,name)
        );

        drop table student;
        
        注意:学生的班级和学生的名字联合起来必须是唯一的(联合唯一)
        注意:联合唯一约束必须使用表级约束来声明
        

        例如7:
        //使用表级约束 声明 联合主键
        create table t_customer(
            id number,
            name varchar2(50),
            primary key(id,name)
        );

        drop table t_customer;


        例如8:
        //使用表级约束 声明 联合外键
        create table t_customer(
            id number,
            name varchar(50),
            primary key(id,name)
        );

        create table t_order(
            id number,
            price number not null,
            customer_id number,
            customer_name varchar(50),
            foreign key(customer_id,customer_name) references t_customer(id,name)
        );


        drop table t_order;
        drop table t_customer;

        
        表级约束和列级约束对比
            1.表级约束和列级约束所写的位置不一样
            2.not null约束不能用表级约束来声明
            3.表级约束和列级约束声明语法稍有所不同
            4.如果要声明的约束为联合主键、联合外键、联合唯一的时候,就一定要用表级约束.


    constraint关键字
        1.constraint是约束的意思
        2.建表的时候可以给约束起一个名字,这个名字起的规律一般会是:表名_列名_约束类型
        3.如果没有给约束起名字,那么系统也会给这个约束起一个默认的名字,这不过这个默认的名字对我们来说并不友好(我们看不懂)
        4.将来我们可以根据我们之前给约束起好的名字而找到这个约束,然后进行修改

        例如1:
        //列级约束 起约束名字
        create table student(
            id number constraint student_id_pk primary key,
            name varchar2(100) constraint student_name_nn not null,
            email varchar2(100) constraint student_email_un unique,
            gender char(1) constraint student_gender_ck check(gender in('f','m')),
            age number,
            birthday date
        );
        
        drop table student;


        例如2:
        //表级约束 起约束名字
        create table t_customer(
            id number,
            name varchar2(20) not null,
            age number,
            email varchar2(100),
            gender char,
            constraint cus_id_pk primary key(id),
            constraint cus_email_un unique(email),
            constraint cus_gender_ck check(gender in('f','m'))
        );

        create table t_order(
            id number,
            price number not null,
            customer_id number,
            constraint order_id_pk primary key(id),
            constraint order_cid_fk foreign key(customer_id) references t_customer(id)
        );
        
        drop table t_order;
        drop table t_customer;





    特殊的建表:建立一张表和s_dept一模一样的表
        例如1:
        //s_dept的表结构和表中的数据全部复制过来
        create table test1
        as
        select * from s_dept;
        
        例如2:
        //只拿来s_dept的表结构,没有数据
        create table test2
        as
        select * from s_dept
        where 1=2;
        
        例如3:
        //只复制表中某几个列以及数据
        create table test3
        as
        select id,last_name,salary from s_emp;


    ON DELETE CASCADE
    on delete cascade
        这个语句是在建表中,声明外键约束的时候一个可选项,我们后面的DML章节中再进一步讨论





第十章:数据字典

    作用:帮助用户了解当前数据库的一些信息或是对象的信息或是用户的信息.
        1.数据字典在数据库被创建时创建的。
        2.数据字典中的数据被数据库服务器自动更新和维护


    
    常见的数据字典(它们都是视图)
    USER开头的视图里面存放着用户自己拥有的对象
    ALL开头的视图存放着用户有权限查看的对象
    DBA开头的视图存放着数据库所有的对象
    V$开头的视图存放数据库运行的一些性能属性数据


    1、以user开头的数据字典: 包含当前用户所拥有的相关对象信息。
        //查询用户拥有的所有表的名字
        select table_name from user_tables;
        
        //查询用户对象表,找出对象类型是TABLE类型的对象名字
        //table view sequence index synonym等都是oracle中的对象
        //注意字符串的值是区分大小写的
        select object_name
        from user_objects
        where object_type = upper('table');
        
        //查询用户对象表,找出对象类型的类型都有哪些
        select distinct object_type
        from user_objects;
        
        //查询出s_emp表中的列及其对应的约束名字
        select constraint_name, column_name
        from user_cons_columns
        where table_name = 'S_EMP';
        
        //查询出s_emp表中的约束名字
        select    constraint_name
        from    user_constraints
        where    table_name = 'S_EMP';
    2、以all开头的数据字典:  包含当前用户有权限访问的所有对象的信息
        //查到当前用户有权限访问的对象
        select table_name from all_tables;  
    3、以dba开头的数据字典:  包含数据库所有相关对象的信息。
        //只能是有dba权限的用户查询,能查到数据库中所有对象
        select table_name from dba_tables; (sys system)

    
    其他视图:DICTIONARY
    dictionary视图中只有俩列:
    TABLE_NAME表示当前表的名字
    COMMENTS表示对这个表的描述

    SQL> desc dictionary
     名称
     -----------------------------------------

     TABLE_NAME
     COMMENTS


    select *
    from dictionary
    where table_name='USER_TABLES';

    select *
    from dictionary
    where table_name='ALL_TABLES';

    select table_name
    from dictionary
    where table_name like 'USER%';

    select table_name
    from dictionary
    where table_name like 'ALL%';


    select table_name
    from dictionary
    where table_name like 'V$%';

    



第十一章:DML语句
    主要内容:
        insert
        update
        delete
        commit
        savepoint
        rollback

    sql语句的分类:
        select查询语句
        DML
        DDL
        DCL
        事务控制语句

    DML: insert update delete
    

    测试使用的表: 没有主外键关联
    create table t_user(
        id number,
        name varchar2(50) constraint user_name_nn not null,
        email varchar2(50),
        gender char(1),
        age number,
        birthday date,
        constraint user_id_pk primary key(id),
        constraint user_email_un unique(email),
        constraint user_gender_ck check(gender in('f','m'))
    );
    drop table t_user;

    insert语句:

        向表中插入数据:
        //默认是向表中的每一个列中【依次】插入数据
        insert into t_user values(1,'tom','abc','f',20,'11-8月-98');
        注:违反任意一种约束那么就插入数据失败

        //也可以指明向表中的哪些列插入数据
        //注意:可以任意交换下面列名的位置,只有values语句中的值也对应交换即可
        insert into t_user(id,name,email,gender,age,birthday) values(2,'tom','abc1','f',20,'11-8月-98');

        //列的值可以是null的话,那么也在插入的时候不指定这个列
        //注意:unique约束和check约束的值,都可以为null
        //注意:主键约束和非空约束的值,都不可以为null
        insert into t_user(id,name,email,gender) values(3,'tom','abc3','f');
        insert into t_user(id,name,email) values(4,'tom','abc3');
        insert into t_user(id,name) values(5,'tom');
        


        //使用运行时参数设置需要输入表中的值
        insert into t_user(id,name) values(&id,'&name');
        


        //把查询的结果 插入到表中
        //前提是查询的列的顺序和要插入表中列的顺序是一致的,这个一致指的的是数据类型是一种的
        insert into t_user(id,name,birthday)
        select id,last_name,start_date
        from s_emp;
    
    
    update语句:
        //修改表中所有数据的age值为20岁
        update t_user set age=20;
        
        //修改表中所有数据的age和gender的值
        update t_user set age=25,gender='m';
        
        //修改表中id小于10数据的age和gender的值为null
        update t_user
        set
        age=null,gender=null
        where id<10;
        
        //修改id为18的用户的名字为zhangsan
        update t_user set name='zhangsan' where id=18;

    
    delete语句
        //删除表中id大于20的用户信息
        delete from t_user where id>20;
        
        //删除名字为张三的用户信息
        delete from t_user where name='zhangsan';
        
        //删除表中所有的数据
        delete from t_user;

    
    
    测试使用的表: 主外键关联
    create table t_customer(
            id number,
            name varchar2(20) constraint customer_name_nn not null,
            constraint customer_id_pk primary key(id)
    );

    create table t_order(
        id number,
        price number,
        customer_id number,
        constraint order_id_pk primary key(id),
        constraint order_cid_fk foreign key(customer_id) references t_customer(id)
    );
    
    drop table t_order;
    drop table t_customer;

    
    insert语句:
        //t_customer表中插入数据
        insert into t_customer(id,name) values(1,'tom1');
        insert into t_customer(id,name) values(2,'tom2');
        insert into t_customer(id,name) values(3,'tom3');

        //t_order表中插入数据
        //customer_id外键列的值必须是t_customer表中出现过的
        insert into t_order(id,price,customer_id) values(1,1000,1);
        insert into t_order(id,price,customer_id) values(2,2000,2);

        //插入出差,因为6这个值并没有在t_customer表中出现过的
        insert into t_order(id,price,customer_id) values(3,3000,6);


        //t_order表中插入数据
        //默认情况下,外键列上的值是可以为空的
        insert into t_order(id,price,customer_id) values(3,3000,null);
        insert into t_order(id,price) values(4,4000);
        注意:如果在外键列上加一个非空约束,那么这个外键列的值就不能为null了(可以给一个列上添加多种约束)


        //t_order表中插入数据
        //默认情况下,外键列上的值是可以重复的
        insert into t_order(id,price,customer_id) values(5,5000,1);
        insert into t_order(id,price,customer_id) values(6,6000,1);
        注意:如果在外键列上加一个唯一约束,那么这个外键列的值就不能重复了(可以给一个列上添加多种约束)

    
    update语句:
        把俩个测试表删除了重新创建,然后向表中插入一些数据
        //t_customer表中插入数据
        insert into t_customer(id,name) values(1,'tom1');
        insert into t_customer(id,name) values(2,'tom2');
        insert into t_customer(id,name) values(3,'tom3');
        //t_order表中插入数据
        insert into t_order(id,price,customer_id) values(1,1000,1);
        insert into t_order(id,price,customer_id) values(2,2000,2);
        
        //把t_order表中id=1的数据的customer_id列修改为3
        update t_order set customer_id = 3 where id = 1;

        //把t_order表中id=1的数据的customer_id列修改为null
        update t_order set customer_id = null where id = 1;
    
        //把t_order表中id=1的数据的customer_id列修改为20
        //sql执行出错,因为就没id=20的顾客
        update t_order set customer_id = 20 where id = 1;
        

    delete语句:
        
        //删除t_order表中的的所有数据
        //可以成功删除,没有问题,因为删除t_order不会对t_costomer表的数据产生任何影响
        delete from t_order;
        
        //t_order表中插入数据
        insert into t_order(id,price,customer_id) values(1,1000,1);
        insert into t_order(id,price,customer_id) values(2,2000,2);

        
        //删除t_customer表中id=3的数据
        //删除成功,因为t_order表中外键列中没有引用过这个值
        delete from t_customer where id = 3;

        //删除t_customer表中id=1的数据
        //删除失败,因为t_order表中外键列中已经引用了这个值
        delete from t_customer where id = 1;

       【在这种情况下,on delete 语句就可以起作用了】



    on delete语句
        on delete no action(默认情况:什么不都写)
        on delete cascade
        on delete set null
        
        on delete语句是在声明外键约束的时候使用的。用户在删除A表中的一条数据,而这条数据被B表中的外键列所引用了,这个时候on delete语句的设置可以告诉oracle这个时候该如何处理
                
        如果在建外键的时候,不加on delete语句,就是on delete no action
        例如1: on delete no action
        create table t_customer(
            id number,
            name varchar2(20) constraint customer_name_nn not null,
            constraint customer_id_pk primary key(id)
        );

        create table t_order(
            id number,
            price number,
            customer_id number,
            constraint order_id_pk primary key(id),
            constraint order_cid_fk foreign key(customer_id) references t_customer(id)
        );
        
        drop table t_order;
        drop table t_customer;

        插入测试数据:
        //t_customer表中插入数据
        insert into t_customer(id,name) values(1,'tom1');
        insert into t_customer(id,name) values(2,'tom2');
        insert into t_customer(id,name) values(3,'tom3');
        //t_order表中插入数据
        insert into t_order(id,price,customer_id) values(1,1000,1);
        insert into t_order(id,price,customer_id) values(2,2000,2);

        //删除失败
        //ORA-02292: 违反完整约束条件 - 已找到子记录
        delete from t_customer where id = 1;

        
        例如2: on delete cascade
        建表语句和测试数据上例1相同,只是在声明外键列的时候加入on delete cascade语句
        create table t_order(
            id number,
            price number,
            customer_id number,
            constraint order_id_pk primary key(id),
            constraint order_cid_fk foreign key(customer_id) references t_customer(id) on delete cascade
        );

            
        //同样做删除测试
        //删除成功,同时级联(cascade)删除了t_order表中所关联的那条数据
        delete from t_customer where id = 1;
        
    

        例如3: on delete set null
        建表语句和测试数据上例1相同,只是在声明外键列的时候加入on delete set null语句
        create table t_order(
            id number,
            price number,
            customer_id number,
            constraint order_id_pk primary key(id),
            constraint order_cid_fk foreign key(customer_id) references t_customer(id) on delete set null
        );

            
        //同样做删除测试
        //删除成功,同时把t_order表中所关联的那条数据的外键设置为了null
        delete from t_customer where id = 1;


    
    数据库事务
        1.DML语句执行的时候,如果当前有事务,那么就使用这个事务,如果当前没有事务,这个执行的DML语句就会产生一个新的事务。
        2.只有DML语句才会产生事务,其他语句不会产生事务。
        3.commit/rollback/DDL语句都可以把当前事务给结束掉
        4.commit和DDL语句结束事务的方式是把这个事务给提交了
        5.rollback结束事务的方式是把这个事务给回滚了
        注:
            提交事务是指让这个事务里面的所有操作都生效到数据库中
            回滚事务是指让这个事务里面的所有操作都撤销
        
        
        测试用的表:
        create table t_customer(
            id number,
            name varchar2(20) constraint customer_name_nn not null,
            constraint customer_id_pk primary key(id)
        );
        drop table t_customer;

        测试: 使用俩个终端窗口,同一个账号登录到数据库中,观察事务是否提交对用户查看数据的影响
        注:一个用户对A表做了DML操作,但是没有提交事务,这时候别的用户是不能对A表再做其他的DML操作。(为了保证数据的安全和一致性)
        

        例如1:
        insert ....产生事务A
        update ... 这个操作是事务A中的操作
        insert ..  这个操作是事务A中的操作
        commit;    让事务A里面的三个操作生效、事务A结束
        delete ... 产生新的事务B
        insert ..  这个操作是事务B中的操作
        insert ..  这个操作是事务B中的操作
        insert ..  这个操作是事务B中的操作
        rollback;  让事务B中的四个操作都撤销,事务B结束


        例如2:
        insert ....产生事务A
        update ... 这个操作是事务A中的操作
        insert ..  这个操作是事务A中的操作
        DDL语句;   事务A会被提交,事务A结束
        rollback;  这时候回滚已经对事务A不起作用,因为事务A以及被提交了,当前已经没有事务了
        
        注:create语句 drop语句 alter语句等都属于DDL语句

    
    事务特征ACID:    
        原子性:Atomicity
            同时成功或者同时失败
        一致性:Consistency
            事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。
        隔离性:Isolation
            事务操作应该相互独立
        持久性:Durability
            事务所做的影响 ,在事务结束之后应该能够是持久的。
    

    isolation  事务隔离级别
        
        事务中产生的问题:

        1.脏读  主要针对update操作。 一个事务A读到另一个事务B中修改过但是还没有提交的数据

        2.不可重复读  主要针对update操作。 一个事务A在第一次读数据和第二次读数据之间,有另一个事务B把这个数据更改并提交了,所以就出现了事务A里面读一个数据俩次,但是读到的结果是不同的。

        3.幻读  主要针对的是insert/delete操作。事务A第一次用where条件筛选出了10条数据,事务A第二次用通样的where条件筛选出的却是11条数据,因为事务B在事务A的第一次和第二次查询之间进行了插入操作,并且插入的这个数据满足事务A的where筛选条件.

        
        事务隔离级别有:
        read-uncommitted  不提交也能读
        read-committed    提交之后才能读 解决了脏读
        repeatable-read   解决了脏读和不可重复读
        serializable      三个问题都解决了

        级别越高解决的问题越多但是效率越低。
        注意:并不是所有数据库都支持这四种事务隔离级别,比如oracle就只支持第二种和第四种这俩种,比如mysql就四种全支持.

        oracle里面默认的事务隔离级别是第二种:read-committed

        oralce里面设置事务隔离级别:
        Set Transaction Isolation Level Read Uncommitted
        Set Transaction Isolation Level Read Committed
        Set Transaction Isolation Level Read Repeatable
        Set Transaction Isolation Level Serializable
    

    回滚点/保存点 savepoint
        例如:
        DML语句1
        savepoint A
        DML语句2
        savepoint B
        DML语句3
        rollback to A/B

        这个时候可以通过这个回滚点让事务回滚到指定的位置,如果不指定回滚点而是直接rollback,那么事务会一下子回滚完.

        【特别注意】:rollback到回滚点之后,这个事务并没结束,这个时候还可以接着回滚或者commit提交事务。
        

        create table t_user(
            id number primary key,
            name varchar2(100),
            salary number
        );
        drop table t_user;
        例如:
        insert into t_user values(1,'tom',1000);
        savepoint A;
        insert into t_user(id,name) values(2,'zs');
        savepoint B;
        delete from t_user;
        rollback to B;

        然后查询看结果
        select * from t_user;




第十二章: 修改表和约束(alter语句)

    测试的表:
    create table t_user(
            id number constraint user_id_pk primary key,
            name varchar2(100),
            salary number
    );
    drop table t_user;

    //在表中添加一个新的列
    alter table t_user
    add birthday date;

    //删除表的某列
    alter table t_user
    drop column birthday;


    //给表中的列添加约束
    //这个约束相当于之前的表级约束
    alter table t_user
    add constraint user_name_un
    unique(name);
    
    //测试刚添加的唯一约束是否生效
    insert into t_user(id,name) values(1,'zs');
    insert into t_user(id,name) values(2,'zs');

    
    //删除表中的约束
    alter table t_user
    drop constraint user_name_un;


    //修改表的名字:
    rename t_user to mytest;
    rename mytest to t_user;

    //修改表中某列的类型
    alter table t_user
    modify (name varchar2(500));


    //让约束失效:必须知道约束的名字
    alter table t_user
    disable constraint user_id_pk cascade;
    
    //测试是否设置成功
    insert into t_user(id,name) values(1,'zs1');
    insert into t_user(id,name) values(1,'zs2');


    //让失效的约束再次生效
    alter table t_user
    enable constraint user_id_pk;


    //截断表中的数据(删除),不需要提交,默认已经提交,并且不能回滚
    truncate table t_user;
    相当于:
    delete from t_user;
    commit;


    //给表添加注释
    comment on table t_user is '很好';
    //给列添加注释
    comment on column t_user.name is 'good';
    //查看表中注释
    select * from user_tab_comments where table_name=upper('t_user');
    //查看列中的注释
    select * from user_col_comments
    where
    comments is not null
    and
    table_name=upper('t_user');





第十三章: 序列
    Sequence 序列
    作用:帮我们生成主键列的值(特点:非空唯一)

    创建序列:
    一般不需要设置sequence的属性,使用默认的方式去创建就可以了.
    create sequence 序列名;

    如果需要设置属性,那么就加上下面的语句.
    [INCREMENT BY n]  每次拿出值加多少
    [START WITH n]    初始值从几开始
    [{MAXVALUE n | NOMAXVALUE}]  最大值
    [{MINVALUE n | NOMINVALUE}]  最小值
    [{CYCLE | NOCYCLE}]  到了最大值后是否循环(如果循环会从1开始)
    [{CACHE n | NOCACHE}] 每次在缓存里面放多少个值.


    例如:创建序列并设置属性
    create sequence seq_test
    increment by 2
    start with 45
    maxvalue 60
    cycle
    nocache;
    
    drop sequence seq_test;

    例如:创建序列使用默认属性
    create sequence seq_test;

    
    对应序列,我们只有俩种操作:
        1.获得序列中的下一个值
            //这个值对于当前这个序列来的其他值来说,肯定是非空唯一
            select seq_test.nextval
            from dual;

        2.查询序列中当前的值是多少
            select seq_test.currval
            from dual;

    
    向t_user表插入数据,其中id值可以需要生成
        create table t_user(
            id number constraint user_id_pk primary key,
            name varchar2(100),
            salary number
        );
        drop table t_user;
    
    //创建序列
    drop sequence t_user_seq;
    create sequence t_user_seq;
    
    //插入数据 使用序列产生id值
    insert into t_user(id,name,salary) values(t_user_seq.nextval,'tom',2000);
    

    通过数据字典查询当前用户的序列
        select sequence_name
        from user_sequences;
    



第十四章: 视图view
    视图就是提取一张或者多张表的数据生成一个映射,操作视图可以达到操作原表的效果,方便数据的管理以及安全操作。

    视图的作用:
        1.隐藏表中的重要数据
        2.代替一些比较长的sql语句

    视图分为俩类:
        简单视图:
           视图所代表的sql中如果没有group by语句,没有组函数,查询的只有一张表,那么这样的视图就是简单视图.
        复杂视图
           视图所代表的sql中如果有group by语句,或者有组函数,或者查询的是多张表,那么这样的视图就是复杂视图.


    简单视图和复杂视图的区别:
        通过简单视图可以修改原来表中的数据,通过复杂视图是不能修改原来的数据的。

    创建视图:
        create or replace view 视图名字
        as
        sql语句
    
    删除视图
        drop view 视图名字;


    测试表:
    create table t_user(
        id number constraint user_id_pk primary key,
        name varchar2(100),
        salary number
    );
    drop table t_user;
    
    插入数据:
    insert into t_user(id,name,salary)
    select id,last_name,salary
    from s_emp;

    //创建视图
    create or replace view v_test
    as
    select *
    from t_user
    where id > 10;

    //查看视图内容
    select *
    from v_test;


    //可以通过*简单视图*对原来的表进行数据的删除/更新/插入
    delete from v_test where id=16;

    update v_test set name = 'zhangsan' where id = 20;

    insert into v_test(id,name,salary) values(28,'tom1',3000);

    

    
    with read only语句
        特点:只能通过视图进行查询数据,不能修改
        例如:
        create or replace view v_test
        as
        select *
        from t_user
        where id > 10
        with read only;
        
        这个视图v_test将来只能查询,不能进行修改





    with check option语句
        特点:通过视图进行的修改 那么也必须可以通过这个视图能够显示出来,要不然就操作失败

    例如:
        //测试用的表及其数据
        drop table t_user;
        create table t_user(
            id number constraint user_id_pk primary key,
            name varchar2(100),
            salary number
        );

        insert into t_user values(1,'tom',1000);
        insert into t_user values(2,'tom2',2000);
        
        
        创建视图:
        create or replace view v_test
        as
        select id,name,salary
        from t_user
        where id=2
        with check option;
        

        //查询视图中的数据
        select * from v_test;

        //插入报错 因为这个操作通过视图显示不出来
        insert into v_test values(3,'tom3',3000);

        //更新失败 因为这个操作通过视图显示不出来
        update v_test
        set name='lily'
        where id=1;

        //更新成功 因为这个操作通过视图可以显示出来
        update v_test
        set name='lily'
        where id=2;

    
    复杂视图
        例如:
            create or replace view v_test
            as
            select avg(salary)
            from t_user
        
        复杂视图只能用来查询,不能修改




第十五章: 索引(index)

    索引的概念:
        1. 类似书的目录结构
        2. Oracle 的"索引"是一种对象,是与表关联的可选对象,能提高SQL查询语句的速度
        3. 索引直接指向包含所查询值的行的位置,减少磁盘I/O
        4. 索引和表是相互独立的物理结构
        5. Oracle 自动使用并维护索引,插入、删除、更新表后,自动更新索引

    索引的创建:
        1.自动创建
            当在表中指定了primary Key或者unique约束时会自动创建唯一值索引。
        2.用户创建。
        用户可以创建非唯一值索引以提高在访问数据时的效率。
        语法:
            create index 索引名
            on 表名(列名);
        例如:
             create index emp_index
             on s_emp(last_name);
        
        删除索引:
            drop index 索引名;
        例如:
            drop index emp_index;

        创建成功后可以通过如下语句查看:
             select index_name from user_indexes;

    给某列创建索引的原则:
        1.列经常作为where子句的限定条件或者作为连接条件
        2.列包含的数据量很大,并且很多非空的值。
        3.两个或者更多列频繁的组合在一起作为where的限定条件或者连接条件
        4.列总是作为搜索条件
        5.索引查出的数据量占2%~4%
        6.索引不是越多越好,不是索引越多越能加速查找。
        7.要索引的表不经常进行修改操作
    
    注意:
        1.在表中的某一个合适的列加入上了索引,那么也只有在数据量很大的时候,才能有所体现出这个查询的效率.
        2.索引一旦建立成功,那么之后这个索引就由系统来管理,我们自己是控制不了的.


    索引的种类:
        Single column 单行索引
        Concatenated  多行索引
        Unique          唯一索引
        NonUnique     非唯一索引
    

    索引结构分为:
        B-tree(默认是这种结构)
            适合大量的增、删、改(OLTP);
            不能用包含OR操作符的查询;
            适合高基数的列(唯一值多)
            典型的树状结构;
        位图
            做UPDATE代价非常高(oracle要根据表的每次修改来更新索引)
            非常适合OR操作符的查询;

        反序
        函数



第十六章: 用户权限控制

    1.创建用户
        create user user_name identified by password
        例如:
        create user zhangsan identified by zhangsan;

    2.删除用户
        drop user zhangsan cascade;

    3.赋予权限
        grant privilege to user;
        例如:把建表 建序列 建视图的权限赋给zhangsan
        grant create table, create sequence,create view to zhangsan;

        //把connect角色和resource角色赋给zhangsan
        //角色是一组权限的集合
        grant connect,resource to zhangsan;


        注意: 只是登陆oracle数据库的话 需要的权限是create session
        
    4.修改密码
        alter user user_name identified by password;

        例如:
        alter user zhangsan identified by zhangsan123;

    5.赋予某一个用户某种对象操作的权限
        grant operator on object to user;
        
        例如:
        grant select
        on t_user
        to briup;

    6.回收权限
        revoke operator on object from user;
        例如:
        revoke select
        on t_user
        from briup;
        
    7.创建同义词synonym
        作用:可以隐藏表原来的信息
        分为:私有同义词 公共同义词

        //给表t_user创建一个私有同义词
        create synonym my_test
        for t_user;
        
        //给用户briup授权可以查询my_test
        grant select
        on my_test
        to briup;

        //收回用户briup查询my_test的权限
        revoke select
        on my_test
        from briup;
        
        //利用数据字典查看同义词synonyms
        //用户创建的同义词有哪些
        select synonym_name
        from user_synonyms;

        //用户有权利查询的同义词有哪些
        select synonym_name
        from all_synonyms;

        //用户有权利查询的同义词有哪些是以字母D开头的
        //注意:表中的数据都是大写存在
        select synonym_name
        from all_synonyms
        where synonym_name like 'D%';
        结果可以看到我们常用的dual

    8.删除同义词synonym
        drop synonym name;

        例如:
        删除私有同义词
        drop synonym my_test;
        删除公共同义词
        drop public synonym your_test;
    
    9.公共的同义词
        因为普通用户没有创建public synonym的权限,所有我们需要用dba的身份登录到数据库中去创建。
        sqlplus "/as sysdba"
        或者system用户登录

        create public synonym your_test
        for test.t_user;

        test.t_user表示的是test用户下面的t_user表


        //让所有人都有查询这个同义词的权限
        grant select on your_test to public;

        然后其他用户登录之后就可以通过这个公共的同义词来查询test用户下面的t_user表了
        
    10,数据库的导入导出
        系统终端执行
          导出:exp   根据提示按回车下一步即可
          导入:imp      根据提示按回车下一步即可



0 0
原创粉丝点击