后台开发必会的Oracle语句

通过select...into 从数据库中查数据对变量进行赋值

declare

name varchar2(50) default 'null';

begin

select sname into name from student where sno='120001'

dbms_output.put_line(name);

end;

 

使用常量计算圆面积

declare

pi constant number:=3.14;

radius number default 5;

area number;

begin

area:=pi*radius*radius;

dbms_output.put_line(area);

end;

 

 

获取当前日期时间

declare

today varchar2(20);

begin

today:=To_CHAR(SYSDATE,'Day');

dbms_output.put_line(‘今天是:’||today);

end;

其中||为字符串连接符

 

将时间进行格式化输出

select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual;

将指定的时间字符串格式化输出

select to_char(to_date('2018-07-30','yyyy-mm-dd'),'yyyy-mm-dd hh24:mi:ss am') from dual;

 

 

student%rowtype 表示其为数据表student的一行

declare

mystu student%rowtype;

begin

select * into mystu from student where sno ='120004';

dbms_output.put_line(mystu.sname);

dbms_output.put_line(mystu.sage);

end;

 

创建基本表

create table stu(

    sno varchar2(10) not null,

    sname varchar2(10),

    sgentle varchar2(2),

    sage number(2),

    sbirth date,

    sdept varchar2(20)

)

增加表字段

alter table stu add major varchar2 (20) default '计算机科学与技术' not null

修改表字段

alter table stu modify sname varchar2(15) default '无' not null

 

重命名基本表

rename stu to stu1

alter stu rename to stu1

 

复制相同结构的表

create table stu1

as

select * from where 1=2

 

创建主键约束

alter table stu add constraint pk_stu primary key(sno)

 

创建外键约束

alter table stu1 add constraint fk_stu foreign key(sno) references stu(sno)

 

删除约束

alter table stu drop constant pk_stu;

 

根据查询结果创建和复制表

create table stu1

as

select * from  stu

where sage  = 22;

(如果只复制表结构不复制表数据,可以使用where rownum<1

使用escape和转义字符

select * from class

where ms like '%0!%' escape '!'

 

查找并替换字符串

select replace(sdept,'计算机','computer') 所在班级 from stu;

 

获取字符的ascii码

select ascii('A') A,ascii('Z') Z,ascii('0') zero from dual;

 

使用round函数精确度数

select round(123.456),

       round(123.456, 2),

       round(123.456, -2),

       round(163.456, -2)

       from dual;

 

add_months函数

select add_months(sbirth,12) from stu;(日期推迟1年)

 

提取日期特定部分

select sysdate 当前日期,extract(year from sysdate) 年份,

extract(month from sysdate)月份,

extract(day from sysdate) 日,

extract(hour from systimestamp)+8 小时,

extract(minute from systimestamp) 分,

extract(second from systimestamp) 秒

from dual;

(使用extract 函数提取当前系统时间的小时值时,hour匹配的结果中没有加上时区,所以小8小时)

 

数据转换类型:

to_char(数字类型转换为字符串类型)

to_number(字符串类型转换为数字类型)

select to_char(1234.567) from dual;

select to_number('1234.567') from dual;

 

获取日期中的某个星期

select to_char(sysdate,’day’) from dual;

 

一年中的第几天

select to_char(sysdate,'DDD') from dual;

 

计算时间差

相差多少天

select floor(to_number(sysdate-to_date('2018-03-04','YYYY-MM-DD'))) as spandays from dual;

相差几个月

select ceil(months_between(sysdate,to_date('2018-03-04','YYYY-MM-DD'))) as spanmonths from dual;

相差年份

select floor(to_number(sysdate-to_date('2014-03-04','YYYY-MM-DD'))/365) as spanyears from dual;

 

获取某月的第一天和最后一天

select trunc(trunc(sysdate, 'month') - 1, 'month') 上月的第一天,

trunc(sysdate,'month')-1/86400 上月的最后一天,

trunc(trunc(sysdate, 'month'), 'month') 本月的第一天,

last_day(trunc(sysdate,'month'))+1-1/86400 本月的最后一天

from dual;

 

获取某一年的天数

select add_months(trunc(sysdate,'year'),12) -trunc(sysdate,'year') from dual

 

nvl函数

nvl(x,value)如果x为空返回value,否则返回x

nvl(x,value1,value2)如果x非空返回value1,否则返回value2

 

找出没有成绩的学生的编号

select sno from stu

minus

select sno from grade;

 

intersect(返回两个查询共有的记录)

union all(返回各个查询的所有记录,包括重复记录)

union(返回各个查询的所有记录,不包含重复记录)

minus(返回第一个查询检索出的记录减去第二个查询检索出的记录)

 

一个表进行自连接

(在stu表中,找出所有年龄相同的学生信息)

select distinct s1.sno,s1.sname,s1.sage

from stu s1 inner join stu s2 on s1.sage = s2.sage

where s1.sno<> s2.sno order by s1.sage desc;

 

创建外键约束

alter table grade add constraint con_grade foreign key(sno) references stu(sno)

 

删除级联数据行

alter table grade drop constraint con_grade

在grade表中创建一个包含

在grade表上重新创建一个包含”on delete cascade”参数的外键约束

alter table grade add constraint con_grade foreign key(sno)

references stu(sno) on delete cascade

当再次删除学生生信息时,成绩表的数据也会连同删除掉

 

防止出现重复值

alter table stu add constraint un_sno unique(sno)

 

控制语句比两个变量的大小

declare

num1 integer:= 10;

num2 integer:= 20;

begin

if num1 > num2 then

dbms_output.put_line('num1大于num2');

else

dbms_output.put_line('num1小于num2');

end if;

end;

 

条件嵌套语句

declare

score integer:=50;

begin

 if score>=80 then

    if score>=90 then

       dbms_output.put_line('优秀');

    else

       dbms_output.put_line('良好');

     end if;

 else

     if score>=70 then

      dbms_output.put_line('中等');

     else

       if score>=60 then

         dbms_output.put_line('及格');

       else

         dbms_output.put_line('不及格');

        end if;

      end if;

  end if;

 end;

       

  使用case语句

 

declare

  score integer:=50;

  begin

   case

    when score>=90 then

     dbms_output.put_line('优秀');

    when (score<90 and score>=80) then

     dbms_output.put_line('良好');

    when (score<80 and score>=70)then

     dbms_output.put_line('中等');

    when (score<70 and score>=60) then

     dbms_output.put_line('及格');

    else

     dbms_output.put_line('不及格');

   end case;

  end;

       

 

loop语句实现累加

declare

  k integer:=0;

  s integer:=0;

begin

  loop

    s:=s+k;

    if k=100 then

       exit;

    else

       k:=k+1;

    end if;

   end loop;

 dbms_output.put_line('共循环次数:'||k);

 dbms_output.put_line('计算结果:'||s);

end;

 

 

for 语句实现累加

declare

  k integer:=1;

  s integer:=0;

  j integer:=0;

begin

  for k in 1..100 loop

      s:=s+k;

      j:=j+1;

  end loop;

  dbms_output.put_line('共循环次数:'||j);

  dbms_output.put_line('计算结果:'||s);

end;

 

创建不带参数的存储过程

create or replace procedure cnum

as

cnumber int;

begin

select count(*) into cnumber from stu;

dbms_output.put_line('stu共有'||cnumber||'行记录');

end cnum;

查询名称为cnum的存储过程内容

select text from user_source where type='procedure' and name='cnum';

 

调用存储过程:

set serveroutput on;

exec cnum;

 

创建带参数的存储过程:

create or replace procedure getclass(snum number)

as

sclass stu.sdept%type;

begin

select sdept into sclass from stu where sno =snum;

dbms_output.put_line(snum||'的学生所在班级'||sclass);

exception

when no_data_found then

dbms_output.put_line('没有找到学号');

end;

调用带参数的存储过程:

exec getclass(12005);

call getclass(12005);

begin

getclass(12005);

end;

 

创建并调用带输出参数的存储过程

create or replace procedure getage(snum in number,age out number)

as

begin

select sage into age from stu where sno = snum;

exception

when no_data_found then

dbms_output.put_line('没有找到学号');

end;

 

declare

age integer;

begin

getage(120005,age);

dbms_output.put_line(age);

end;

 

 

查看存储过程的内容:

select text from user_resource

where type=’procedure’ and (name=’getage’ or name =’addstu’)

 

重新编译存储过程

alter  procedure getage compile

 

删除存储过程

drop procedure addstu;

 

动态sql执行ddl语句

create or replace procedure proc_test

(

       table_name in varchar2,

       field1 in varchar2,

       datatype1 in varchar2,

       field2 in varchar2,

       datatype2 in varchar2

)as

   str_sql varchar(500);

begin

   str_sql:= 'create table '||table_name||'('||field1||' '||datatype1||','||field2||' '||datatype2||')';

   execute immediate str_sql;

   exception

        when others then

   null;

end;

调用存储过程创建表

exec proc_test('testsql','id','number(8) not null','name','varchar2(100)');

 

 

动态sql执行dml语句

create or replace procedure proc_insert

(

       id in number,

       name in varchar2

)as

str_sql varchar(500);

begin

    str_sql:='insert into testsql values(:1,:2)';

    execute immediate str_sql using id,name;

    exception

        when others then

             null;

end;

execute proc_insert(1,'LiLy');

 

创建触发器

 

create or replace trigger tri_yj

   before update on stu

   begin

   if updating then

   dbms_output.put_line('除非语句触发器');

   end if;

   end;

 

语句触发触发器

set serveroutput on ;

update stu set sage = age +1 where sage =26;

 

查看触发器:

select trigger_name,trigger_type from user_triggers

where table_name =’stu’

select text from user_source where type = ‘trigger’

and name=’tri_yj’;

 

创建并触发行触发器

create or replace trigger tri_hj

after update on stu

for each row

begin

if updating then

dbms_output.put_line('改行记录已更新');

end if;

end;

 

insert触发器

create or replace trigger tri_in

after insert on stu

begin

dbms_output.put_line('已插入一行');

end;

 

update指定列触发器

create or replace trigger tr_up

before update of sno

on stu

for each row

begin

raise_application_error(-20001,'不能修改sno列的数据')

end;

 

创建instead of 触发器

create or replace trigger tri_inof

instead of insert on v_grade

for

each row

begin

insert into stu(sno,sname.sage,sdept)

values(:NEW.学号,:NEW.姓名,:NEW.年龄,'12计算机')

insert into grade(sno,cname,score)

values(:NEW.学号,:NEW.课程,:NEW.成绩);

end;

insert into v_grade values(‘120008’,’XX’,21,’XX’,88);

 

创建用户事件触发器

create or replace trigger tri_yh

after ddl on schema

begin

dbms_output.put_line('执行了ddl语句');

end;

 

创建系统事件触发器

create table logon_event

(user_name varchar2(10),

address varchar2(20),

logon_date timestamp,

logoff_date timestamp);

create or replace trigger tri_xt

after logon on database

begin

      insert into logon_event(user_name,address,logon_date)

      values(ora_login_user,ora_client_ip_address,systimestamp);

end;

 

禁用和启用触发器

alter trigger tri_yj disable;

alter trigger tri_yj enable;

将删除记录自动写入记录表

create table del_tmp as

select * from stu where 1=2;

create or replace trigger tri_del_tmp

  before delete

  on stu

  for each row

begin

  insert into del_tmp

  values(:OLD.sno,:OLD.SNAME)

end;

 

限制非工作时间操作数据

create or replace trigger tri_sjxz

before insert or delete or update

on stu

begin

   if(to_char(sysdate,'day')in('星期六','星期天'))or

   (to_char(sysdate,'HH24:MI') not between '9:00' and '18:00')

   then  raise_application_error(-20001,'不是上班时间,不能修改stu表');

   end if;

end;

 

实现级联更新

create or replace trigger tr_jlgx

after update of sno

on stu

for each row

begin

 dbms_output.put_line('旧值'||:OLD.sno||'新值'||:NEW.sno);

 update grade set sno = :NEW.sno

 where sno = :OLD.sno;

end;

 

创建数据对象结果操作事件日志

create table ddl_event

(crt_event timestamp primary key,

 event_name varchar2(20),

 user_name varchar2(10),

 obj_type varchar2(20),

 obj_name varchar2(20));

 

 create or replace  trigger tr_ddl

 after ddl on schema

 begin

       insert into ddl_event values

       (systimestamp,ora_sysevent,ora_login_user,

       ora_dict_obj_type,ora_dict_obj_name);

 end;

 

删除触发器

drop trigger tri_yj

 

事务提交:

commit;

事务回滚:

rollback;

设置保存点:

savepoint UPDATEPOINT(这样每次可以回滚到某个保存点,不比回滚整个事务,

即使设置了保存点,也并不代表保存点之前的操作不需要commit)

 

回滚部分事务

insert ...

update ...

savepoint updatepoin

delete ...

rollback to updatepoin

将会发现删除的数据恢复,插入和更新依然执行

 

DDL语句对事务的影响

alter table 语句是一条DDL语句(DDL,DCL语句能够对未提交的事务进行提交)

 

知识小科普

DDL:数据库模式定义语言,关键字:create COMMIT DROP
DML:数据操纵语言,关键字:Insert、delete、update
DCL:数据库控制语言 ,关键字:grant、remove
DQL:数据库查询语言,关键字:select

exit命令断开数据库连接会自动提交事务

如果用户非正常断开服务器,事务会被自动回滚。

 

select * from stu where sname=’李遂’ for update

(select 语句后加for update 参数 ,表示该语句查询到的记录上加锁,这时第二个SQL*Plus用户试图对该记录进行update 操作时就被卡住了)

锁定数据表(当其他用户想操作该表就会被锁住)

lock table stu in exclusive mode;

查看被锁定的数据对象

select oracle_username,object_id,session_id

from v$locked_object;

select object_name,object_type from dba_objects where object_id=''

 

 

为被锁定表解锁:

  1. 对试图V$SESSION 进行查询操作,找出被锁定对象的session_id对应当前运行的进程号

select sid,serial#,program from V$SESSION WHERE SID = '';

  1. 使用kill命令结束对应的进程

ALTER SYSTEM KILL SESSION '148,1009' ;(sid,SERIAL#)

重复执行步骤1,2,直到试图V$LOCKED_OBJECT 中被锁定stu表所对应的session_id全部被结束为止。

只要不是异常关闭数据库连接,锁定的数据对象会在重新连接后自动解锁。

 

  1. 创建程序包(是一组相关过程,函数,变量,常量和游标等PL/SQL程序设计元素的结合):

create or replace package stu_pkg

is

  stu_rec stu%rowtype;

  procedure delete_stu(sno in number);

  procedure query_stu(sno in number);

end stu_pkg;

  1. 创建包主体:

create or replace package body stu_pkg

is

procedure delete_stu(sno in number)

is

begin

 delete from stu where sno = sno;

 if sql%found then

   dbms_output.put_line('数据库中没有学号为'||sno||'的学生');

 else

   dbms_output.put_line('删除成功');

  end if;

 exception

   when others then

    dbms_output.put_line('操作异常')

end delete_stu;

 

procedure query_stu(sno in number)

is

begin

  select * into stu_rec from stu where sno = sno;

exception

  when no_data_found then

    dbms_output.put_line('数据库中没有学号为'||sno||'的学生');

  when too_many_rows then

     dbms_output.put_line('程序运行错误');

  when others then

     dbms_output.put_line(SQLCODE||'----'||SQLERRM);

end query_stu;

begin

    null;

end stu_pkg;

 

使用程序包:

set serveroutput on

begin

stu_pkg.query_stu('12001');

dbms_output.put_line(stu_pkg.stu_rec.sno);

stu_pkg.delete_stu('120001');

end;

 

删除程序包:

drop package stu_pkg;(删除整个包)

删除包体

drop package body stu_pkg;

 

游标

 

声明游标:
declare

cursor cur_stu

is

select * from stu;

begin

dbms_output.put_line('游标已声明');

end;

 

打开游标

open cur_stu;

 

提取数据:

declare

c_no stu.sno%type;

c_name stu.sname%type;

cursor cur_stu

is

select sno,sname from stu order by sno;

begin

open cur_stu;

fetch cur_stu into c_no,c_name;

dbms_output.put_line('学号'||c_no||'姓名'||c_name);

fetch cur_stu into c_no,c_name;

dbms_output.put_line('学号'||c_no||'姓名'||c_name);

fetch cur_stu into c_no,c_name;

dbms_output.put_line('学号'||c_no||'姓名'||c_name);

end;

关闭游标

close cur_stu;

 

循环语句中的游标使用:

declare

c_no stu.sno%type;

c_name stu.sname%type;

cursor cur_stu

is

select sno,sname from stu order by sno;

begin

   open cur_stu;

    loop

     fetch cur_stu into c_no,c_name;

     exit when cur_stu%notfound;

      dbms_output.put_line('学号'||c_no||'姓名'||c_name);

     end loop;

    close cur_stu;

end;

 

游标提取整行数据:

declare

stu_row stu%rowtype;

cursor cur_stu

is

select * form stu;

begin

  open cur_stu;

    loop

      fetch cur_stu into stu_row;

      exit when cur_stu%notfound;

      dbms_output.put_line(stu_row.sno||' '||stu_row.sname);

     end loop;

    close cur_stu;

end;

 

带参数的游标:

declare

 

cursor cur_stu(dept varchar2)

is

select * form stu where sdept = dept;

stu_row cur_stu%rowtype;

begin

  open cur_stu('12工商管理');

    loop

      fetch cur_stu into stu_row;

      exit when cur_stu%notfound;

      dbms_output.put_line(stu_row.sno||' '||stu_row.sname);

     end loop;

    close cur_stu;

end;

 

使用参数为变量的游标:

declare

cursor cur_stu

is

  select sno

  from stu order by sno;

cursor cur_grade(c_sno varchar2)

is

  select * from grade;

c_sno stu.sno%type;

g_row grade%rowtype;

begin

  open cur_stu;

    loop

      fetch cur_stu into c_sno;

      exit when cur_stu%notfound;

      open cur_grade(c_sno);

        loop

          fetch cur_grade into g_row;

          exit when cur_grade%notfound;

          dbms_output.put_line(g_row.sno||' '||g_row.sname);

        end loop;

        close cur_grade;

     end loop;

   close cur_stu;

end;

 

 

使用游标for循环

declare

cursor cur_stu

is

select sno,sname,sdept from stu;

stu_row stu%rowtype;

begin

for stu_row in cur_stu

loop

dbms_output.put_line(stu_row.sno||' '||stu_row.sname);

end loop;

end;

 

使用游标更新数据:

declare

cursor cur_stu

is

select * from stu for update;

stu_row stu%rowtype;

begin

open cur_stu;

loop

fetch cur_stu into stu_row;

exit when cur_stu%notfound;

update stu set sage = sage +1 where current of cur_stu;

end loop;

close cur_stu;

end;

 

使用游标删除数据:

declare

cursor cur_stu

is

select * from stu for update;

stu_row stu%rowtype;

begin

open cur_stu;

loop

fetch cur_stu into stu_row;

exit when cur_stu%notfound;

if stu_row.sno ='120008' then

delete from  stu where current of cur_stu;

end loop;

close cur_stu;

end;

 

游标的属性

%found %notfound %isopen %rowcount(游标读取的记录数)

 

使用rowid高效删除重复记录

delete from stu s

where s.rowid >(selectmin(T.rowid) from stu t

where t.sno = s.sno)

 

使用truncate代替delete删除记录

truncate table stu;

 

高效统计记录行数:

select table_name,num_rows

from user_tables

where table_name =’stu’

 

使用exists代替in(exists的子查询不返回任何实际数据,只返回逻辑值true,false,而in子查询返回集合数据)

 

用>=代替>运算符

oralce在执行>=运算符时,直接跳到第一个日期等于当天时间的记录再进行统计,而>运算符,首先定位到日期大于当天的记录并且向前扫描到第一个日期小于当天的记录为止,>=无须逐行比较。

 

避免distinct(distinct 用二重循环查询来实现消除重复记录,这需要对数据表中的每个记录都进行比较)

 

用索引提高效率(oracle 使用的是一个复杂的子平衡B-tree结构)

创建索引

create index index_sage on stu(sage);

select * from stu where sage >22;

注:使用索引 需要空间来存储,也需要定期维护,每当有记录在表中增减或索引列被修改时,索引本身也会被修改,因此需定期重构。

 

 

避免在索引列上进行运算

如果在select语句的where 子句中,索引列是函数的一部分,或者是在索引列上进行了运算,Oracle优化器将不用索引而仍使用全表扫描,此时索引将失效。

在Oracle中,如果用户需要找出哪些语句执行效率极差,从而有针对性地进行优化,一般可以对正在运行的语句查看执行计划。

explain plan for select * from test1;

select * from table(dbms_xplan.display);

 

在索引列上用union替换or(使用索引列使用or运算符将进行全表扫描)

select * from stu where sno=’12222’ or sage>22;

select * from stu where sno=’12001’ union select * from stu where sage>22;

 

避免在索引列上用is null,is not null.

 

使用where 子句优化group by

select * from log_event group by user_name having user_name =’sys’ or user_name=’sys’

 

select * from log_event where user_name =’sys’ or user_name=’sys’

group by user_name

 

 

处理预定义异常:

declare

stu_rec stu%rowtype

begin

  select * into stu_rec from stu where sage>22;

  exception

    when too_many_rows then

    dbms_output.put_line('返回的记录太多了');

    when others then

      dbms_output.put_line('未知异常');

end;

 

处理自定义异常:

declare

  stusage stu.sage%type;

  myexp exception;

begin

  select sage into stusage from stu where sno='120001';

  if stusage =22 then

     raise myexp;

  end if;

  exception

      when on_data_found then

      dbms_output.put_line('没有找到该学生');

      when myexp then

      dbms_output.put_line('该学生年龄错误');

end;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值