zoukankan      html  css  js  c++  java
  • 笔记11:Oracle基础

    Oracle基础

    单行函数:

    作用于一行,返回一个值

    • 字符函数
    select upper("yse") from dual;--结果:YES
    select lower("YES") from dual;--结果:yse
    
    • 数值函数
    select round(26.18,1) from dual; --四舍五入,后面参数表示保留的小数, 整数==往后保留,负数==往前保留
    select trunc(56.16,1) from dual; --直接截取,不再看后面位数是否大于5
    select mod(10,3) from dual; --求模(取余) 结果:1
    
    • 日期函数
    --查询出emp表中所有员工入职距离现在几天
    select sysdate-e.hiredate 
    from emp e;--sysdate==当前系统时间
    
    --算出明天此刻
    select sysdate+1 
    from dual;
    
    --查询出emp表中所有员工入职距离现在几月
    select months-between(sysdate,e.hiredate) 
    from emp e;
    
    --查询出emp表中所有员工入职距离现在几年
    select months-between(sysdate,e.hiredate)/12 
    from emp e;
    
    --查询出emp表中所有员工入职距离现在几周
    select round((sysdate-e.hiredate)/7) 
    from emp e;round()==四舍五入函数
    
    • 转换函数
    --时间转字符串格式
    select to_char(sysdate,'fm yyyy-mm-dd hh24:mi:ss') 
    from dual;  fm==时分秒前不加0 24==24小时制
    
    --字符串转日期
    select to_char('2020-7-13 22:41:21','fm yyyy-mm-dd hh24:mi:ss') 
    from dual;
    
    • 通用函数
    -- 算出emp表中所有员工的年薪
    --sal=月薪字段 e=emp的别名 comm=一年的奖金
    select e.sal*12+e.comm
    from emp e; 
    
    --奖金里面有null时,null值和任意数字做算数运算,结果都是null
    --解决:nvl()函数:如果值为null用0代替
    select e.sal*12+nvl(e.comm,0)
    from emp e;
    

    多行函数

    作用于多行,返回一个值

    方法
    count(1) 查询总数量,
    1= * 表示主键即所有
    sum('字段') 求和
    max('字段') 最大值
    min('字段') 最小值
    avg('字段') 平均值

    分组查询

    -- 查询出每个部门的平均工资
    select e.deptno, avg(e.sal) --如果加这段:,e.ename 则报错
    from emp e 
    group by e.deptno
    
    • 分组查询中,出现在group by后面的原始列,才能出现在select后面
    • 没有出现在group by后的列,想在select后面出现,必须加上聚合函数
    • 聚合函数有一个特性,可以把多行记录变成一个值
    --查询出平均工资高于2000的部门信息
    select e.deptno, avg(e.sal) asal  --如果加这段及haveing后面用asal来判断则报错
    from emp e
    group by e.deptno
    having avg(e.sal)>2000;
    
    • 所有条件都不能使用别名来判断。

    如:select ename,sal s from emp where s>1500; --会报错,s别名不能用来判断

    where和having的区别

    • where是过滤分组前的数据,having是过滤后的数据
    • 表现形式:where 必须是在group by之前,having是在group by之后

    子查询

    子查询返回一个值

    -- 查询工资和员工SCOTT一样的员工信息
    select * 
    from emp 
    where sal = (-- 由于ename字段不是主键,姓名为'SCOTT'的数据可能不止一条,所以上面用等号有时会有问题 解决:用in代替等号即可
        select sal 
        from emp 
        where ename = 'SCOTT';
    )
    

    子查询返回一个集合

    -- 查询出工资和10号部门任意员工一样的员工信息
    select * 
    from emp 
    where sal in (
        select sal 
        from emp 
        where deptno = 10;
    ) -- deptno==部门编号
    

    子查询返回一张表

    -- 查询出每个部门最低工资,和最低工资员工姓名,和该员工所在部门名称
    -- 三表联查,得到最终结果
    select t.deptno ,t.msal,e.ename,d.dname
    from(
        select deptno min(sal) msal --1-先查询每个部门最低工资 msal==最小工资字段别名
        from emp
        group by deptno
    ) t,emp e,dept d
    where t.deptno = e.deptno and t.msal = e.sal and e.deptno = d.deptno;
    

    oracle分页

    rownum行号:当我们做select操作的时候,每查询出一行记录,就会在该行上加一个行号,行号从1开始,依次递增,不能跳着走

    -- 例:emp表工资倒叙排序后,每页五条记录,查询第二页
    -- 第二页即:行号为6-10
    
    -- 说明:排序操作会影响rownum的顺序 如:
    select * 
    from emp e 
    where rownum < 4 
    order by e.sal desc; --查询排序后的前三条
    
    解决:	
    select rownum,t.* 
    from(
        select * 
    	from emp e 
    	order by e.sal desc
    ) t 
    where rownum<4;  -- 先排序再加行号
    
    
    -- 说明:rownum行号不能使用大于>
    select rownum,e.* 
    from(select * 
    	 from emp e 
    	 order by e.sal desc
    ) 
    where rownum<11 and rownum>5 -- 查询无数据
    		
    
    -- 正确分页查询语句:
    select *
    from(
    	select rownum rn,tt.*
    	from(
    		select *
    		from emp
    		order by sal desc
        ) tt
    	order by e.sal desc
    	where rownum<11
    )
    where rn>5;
    

    视图

    概念:视图就是提供一个查询的窗口,所有数据来自于原表

    视图的作用:

    • 视图可以屏蔽掉一些敏感字段。
    • 保证总部和分部数据及时统一。
    --查询语句创建表
    create table emp 
    as 
    select * 
    from scott.emp; --scott==用户名
    
    -- 查询
    select * 
    from emp;
    
    
    --创建视图[必须有dba权限]
    create view v_emp 
    as 
    select ename,job 
    from emp;
    
    --查询视图
    select * from v_emp;
    
    --修改视图(不推荐)
    update v_emp 
    set job='CLERK'
    where ename='ALLEN';--原表数据也被修改
    commit;
    
    --创建只读视图
    create view v_emp1 
    as 
    select ename,job 
    from emp with read only;--无法修改
    

    索引

    概念:索引就是在表的列上构建一个二叉树。达到大幅度提高查询效率的目的,但是索引会影响增删改的效率

    单列索引

    -- 创建单列索引
    create index idx_ename on emp(ename);
    
    -- 触发规则:条件必须是索引列中的原始值。
    -- 单行函数,模糊查询 都会影响索引的触发
    select * from emp where ename='SCOTT';
    

    复合索引

    --创建复合索引
    create index idx_enamejob on emp(ename,job);
    		
    --触发规则:复合索引中第一列为优先检索列。如果要触发复合索引,必须包含有优先检索列中的原始值
    select * from emp where ename='SCOTT' and job='xxx'; --会触发复合索引,有优先检索列ename='SCOTT'
    select * from emp where ename='SCOTT' or job='xxx';  --不触发索引。相当于两个语句,一个触发一个不触发即不触发。
    select * from emp where ename='SCOTT'; 				 --触发的是单列索引,既有单列也有复合,但查询为单列
    

    pl/sql编程语言

    • 是对sql语言的扩展,是sql语言具有过程化编程的特性。
    • 比一般的过程化编程语言更灵活高效。
    • 主要用来编写存储过程和存储函数等。

    声明方法:

    declare
    	--定义一个数字变量i赋值为10
    	i number(2) := 10; 
    	
    	--定义字符串变量s赋值为小明
    	s varchar2(10) := '小明'; 
    	
    	--引用型变量,定义一个emp表中ename字段类型的变量ena
    	ena emp.ename%type; 
    	
    	--记录型变量,定义一个存emp表中一行记录的变量,相当于一个对象
    	emprow emp%rowtype; 
    begin
    	
    	dbms_output.put_line(i); --输出变量i 结果:10
    	dbms_output.put_line(s); --输出变量s 结果:小明
    	
    	select ename into ena 
    	from emp 
    	where empno=7788; --从emp表中查询一个姓名赋值给变量ena
    	dbms_output.put_line(ena); --输出变量ena
    	
    	select * into emprow 
    	from emp 
    	where empno=7788;
    	dbms_output.put_line(emprow.ename ||'的工作为:'|| emprow.job); --结果例如==SCOTT的工作为:ANALYST
    	
    end;
    
    --总结:
    赋值操作可以用【:=】也可以用【into查询语句】赋值
    

    流程结构:

    if判断:

    --输入小于18的数字,输出未成年;输入大于18小于40数字,输出中年人;输入大于40的数字,输出老年人
    declare
    	i number(3) := &ii; --输入一个数值类型的数据并赋值给i
    begin
    	if i<18 then
    		dbms_output.put_line('未成年');
    	elsif i<40 then
    		dbms_output.put_line('中年人');
    	else
    		dbms_output.put_line('老年人');
    	end if;
    end;
    

    loop循环:

    --用三种方式输出1-10
    -------------------------------------------while循环
    declare
    	i number(2) :=1;
    begin
    	while i<11 loop
    		dbms_output.put_line(i);
    		i := i+1;
    	end loop;
    end;
    -------------------------------------------exit循环
    declare
    	i number(2) :=1;
    begin
    	loop
    		exit when i>10;
    			dbms_output.put_line(i);
    			i := i+1;
    	end loop;
    end;
    -------------------------------------------for循环
    declare
    	
    begin
    	for i in 1..10 loop
    		dbms_output.put_line(i);
    	end loop;
    end;
    

    游标

    概念:可以存放多个对象,多行记录,相对于集合

    -- 输出emp表中所有员工的姓名及工作
    declare
    	cursor c1 is 
    	select * 
    	from emp; --定义了一个游标c1,并把emp表中所有数据存入了游标
    	
    	emprow emp%rowtype; --记录型变量,定义一个存emp表中一行记录的变量,相当于一个对象
    begin
    	open c1;--打开游标
    		loop
    			fetch c1 into emprow; --把emp一行数据复制给变量emprow
    			exit when c1%notfound; --当游标找不到数据即最后一行时退出循环
    			dbms_output.put_line(emprow.ename ||'--'|| emprow.job);
    		end loop;
    	close c1;--关闭游标
    end;
    
    --给指定部门员工涨工资
    declare
    	cursor c2(eno emp.deptno%type) is 
    	select empno 
    	from emp 
    	where deptno=eno; --定义了一个游标并需要传入一个参数eno
    	
    	en emp.empno%type;
    begin
    	open c2(10);--打开游标并传入参数10
    		loop
    			fetch c2 into en;
    			exit when c2%notfound;
    			update emp set sal = sal+100 where empno = en;
    			commit;
    		end loop;
    	cloce c2;
    end;
    

    存储过程

    概念:存储过程就是提取已经编译好的一段pl/sql语言,放置在数据库端,可以直接被调用,这一段pl/sql一般都是固定步骤的业务。

    --创建存储过程语法: 
    create [or replace] procedure 过程名[参数名 in/out 数据类型...]
    AS 或 is
    begin
    	plsql子程序体;
    end;
    
    -- 例:给指定员工涨100块钱
    create or replace procedure pl(eno emp.empno%type) --or replace表示如果已经存在该存储过程仍可以正常执行
    is
    begin
    	update emp set sal = sal+100 where empno = eno;
    	commit;
    end;
    
    --测试存储过程p1
    declare
    begin
    	pl(7788); --结果:员工编号为7788的员工工资涨100
    end;
    

    out类型参数如何使用

    --使用存储过程来算年薪
    create or replace procedure p_yearsal(eno emp.empno%type,yearsal out number) --yearsal out number表示yearsal参数为输出参数
    is
    	s number(10); --存放工资
    	c emp.comm%type; --存放奖金
    begin
    	select sal*12,nvl(comm,0) into s,c 
    	from emp 
    	where empno=eno;
    	yearsal := s+c;
    end;
    
    
    --测试存储过程p_yearsal
    declare
    	yearsal number(10); --定义变量放入存储过程改变其值
    begin
    	p_yearsal(7788,yearsal); --yearsal的值在存储过程内被改变
    	dbms_output.put_line(yearsal); --结果:输出员工编号为7788的员工的年薪
    en
    

    in和out类型参数的区别:凡是涉及到into查询语句赋值或 := 赋值操作的参数,都必须使用out来修饰 否则其余都用in

    存储函数

    与存储过程区别:

    • 存储函数可以有一个返回值,而存储过程没有
    • 存储过程和存储函数的参数都不能带长度
    • 存储函数的返回值类型不能带长度
    --通过存储函数实现计算指定员工的年薪
    create or replace function f_yearsal(eno emp.empno%type) return number --这里参数和返回值类型不能带长度
    is
    	s number(10);
    begin
    	select sal*12+nvl(comm,0) into s 
    	from emp
        where empno = eno;
    	return s;
    end;
    
    --测试存储函数f_yearsal
    --存储函数在调用的时候,返回值需要接收,不接受会报错
    declare
    	sal_year number(10);
    begin
    	sal_year := f_yearsal(7788); 
    	dbms_output.put_line(sal_year);--结果:输出员工编号为7788的员工的年薪
    end;
    

    存储过程和存储函数的区别:

    • 语法:
      • 关键字不一样
      • 存储函数比存储过程多了两个return
    • 本质区别:
      • 存储函数有返回值,二存储过程没有返回值
      • 如果存储过程想实现有返回值的业务,我们就必须使用out类型的参数
      • 即便是存储过程使用out类型的参数,其本质也不是真的有了返回值
      • 而是在存储过程内部给out类型参数赋值,在执行完毕后,我们直接拿到输出类型参数的值。

    触发器

    制定一个规则,在【增删改】操作的时候,只要满足该规则,自动触发,无需调用。

    • 语句级触发器:不包含有for each row的
    -- 例:插入一条记录,输出'创建xxx'
    
    --创建一个触发器t1
    create or replace trigger t1
    after 		--语句执行前还是后执行该触发器
    insert		--执行什么语句会触发
    on person	--作用哪个表的触发器
    declare
    begin
      dbms_output.put_line('创建了一个person');
    end;
    
    --触发t1
    insert into person(pid, name, gender, birthday) values(2, '李四', 1, to_date('2020-7-17', 'yyyy-MM-dd'));
    
    • 行级触发器:

      包含有for each row的就是行级触发器。

      加for each row是为了使用 :old 或者 :new 对象获取一行记录

    -- 例:不能给员工降薪
    create or replace trigger t2
    before
    updater
    on emp
    for each row --表示行级触发器
    declare
    
    begin
    	if :old.sal > :new.sal then
    		-- 抛出一个异常raise_application_error(-20001~-20999之间,'错误提示信息');
    		raise_application_error(-20001,'不能给员工降薪');
    	end if;
    end;
    
    -- 例:使用触发器实现主键自增
    --分析:在用户插入操作之前,拿到即将插入的数据,给该数据中的主键列赋值,使用该功能用到行级触发器
    create or replace trigger auid
    before
    insert
    on person
    for each row
    declare
    
    begin
    	select s_id_person.nextval into :new.pid from dual;
    	--s_person 自定义序列号名字 
    	--nextval 取序列的下一个值 
    	--dual 是oracle的bai虚拟表du,不是真实存在的
    end;
    

    java调用存储过程或存储函数

    --需要jar包
    	oracle10g == ojdbc14.jar
    	oracle11g == ojdbc6.jar
    --需要接口
    	CallableStatement
    
    public class OracleDemo {
    	//测试连接oracl数据库
    	@Test
    	public void javaCallOracle() throws Exception {
    		//加载数据库驱动
    		Class.forName("oracle.jdbc.driver.OracleDriver");
    		//得到Connection连接
    		Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@192.168.88.6:1521:orcl",
    				"root", "root");
    		//得到预编译的Statement对象
    		PreparedStatement pstm = connection.prepareStatement("select * from emp where empno = ?");
    		//给参数赋值
    		pstm.setObject(1, 7788);
    		//执行数据库查询操作
    		ResultSet rs = pstm.executeQuery();
    		//输出结果
    		while(rs.next()){
    			System.out.println(rs.getString("ename"));
    		}
    		//释放资源
    		rs.close();
    		pstm.close();
    		connection.close();
    	}
        
    	/**
    	 * java调用存储过程
    	 * {?= call <procedure-name>[(<arg1>,<arg2>, ...)]}   调用存储函数使用
    	 * {call <procedure-name>[(<arg1>,<arg2>, ...)]}   调用存储过程使用
    	 * @throws Exception
    	 */
    	@Test
    	public void javaCallProcedure() throws Exception {
    		//加载数据库驱动
    		Class.forName("oracle.jdbc.driver.OracleDriver");
    		//得到Connection连接
    		Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@192.168.88.6:1521:orcl",
    				"root", "root");
    		//得到预编译的Statement对象
    		CallableStatement pstm = connection.prepareCall("{call p_yearsal(?, ?)}");//call p_yearsal(?, ?)为存储过程,带两个参数
    		//给参数赋值
    		pstm.setObject(1, 7788);//第一个参数,查询的id
    		pstm.registerOutParameter(2, OracleTypes.NUMBER);//无返回值,第二参数表示输出类型的参数==员工年薪
    		//执行数据库查询操作
    		pstm.execute();
    		//输出结果[第二个参数]
    		System.out.println(pstm.getObject(2));
    		//释放资源
    		pstm.close();
    		connection.close();
    	}
        
    	/**
    	 * java调用存储函数
    	 * {?= call <procedure-name>[(<arg1>,<arg2>, ...)]}   调用存储函数使用
    	 * {call <procedure-name>[(<arg1>,<arg2>, ...)]}   调用存储过程使用
    	 * @throws Exception
    	 */
    	@Test
    	public void javaCallFunction() throws Exception {
    		//加载数据库驱动
    		Class.forName("oracle.jdbc.driver.OracleDriver");
    		//得到Connection连接
    		Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@192.168.88.6:1521:orcl",
    				"root", "root");
    		//得到预编译的Statement对象
    		CallableStatement pstm = connection.prepareCall("{?= call f_yearsal(?)}");
    		//给参数赋值
    		pstm.setObject(2, 7788);  //第二个?表示存储函数参数==查询的id
    		pstm.registerOutParameter(1, OracleTypes.NUMBER);//第一?表示存储函数返回值
    		//执行数据库查询操作
    		pstm.execute();
    		//输出结果[第一个参数]
    		System.out.println(pstm.getObject(1));
    		//释放资源
    		pstm.close();
    		connection.close();
    	}
    }
    
  • 相关阅读:
    Android 2.2 r1 API 中文文档系列(11) —— RadioButton
    Android API 中文 (15) —— GridView
    Android 中文 API (16) —— AnalogClock
    Android2.2 API 中文文档系列(7) —— ImageButton
    Android2.2 API 中文文档系列(6) —— ImageView
    Android 2.2 r1 API 中文文档系列(12) —— Button
    Android2.2 API 中文文档系列(8) —— QuickContactBadge
    [Android1.5]TextView跑马灯效果
    [Android1.5]ActivityManager: [1] Killed am start n
    Android API 中文(14) —— ViewStub
  • 原文地址:https://www.cnblogs.com/xiaoaiying/p/13344656.html
Copyright © 2011-2022 走看看