Oracle培训—案例整理

1. 概述

Oracle培训共计8堂课,计划有6个案例,但是我整理过程中发现好像是4个大的案例:
1)停车收费模型-批量导入数据
2)导入千万数据(导数据、索引)
3)多人聊天(权限、视图、函数)
4)超市购物(存储过程)

2 .停车收费模型(拼接导入、union、group by)

2.1批量导入2001条数据

问题:如果BOSS给你一个TXT数据文件(2001条),如何考虑用最短的时间导入在用数据库,使之参与业务应用;
格式见下图:


Oracle培训—案例整理_第1张图片
原始数据.png

操作步骤:
1.创建数据库表

--创建(也叫定义)表
CREATE TABLE car_info(
carid VARCHAR2(20) NOT NULL,
intime DATE NOT NULL,
outtime DATE);

2.把.txt文件导入到excel中,在excel中拼接insert语句:

Oracle培训—案例整理_第2张图片
拼接语句.png

最后把excel中的语句复制到txt文件里面,形成car.sql文件存放在d:\car.sql。
3.导入car.sql到数据库的car_info表
sql> @d:\car

Oracle培训—案例整理_第3张图片
统计.png

2.2 业务问题

  1. 查找7:00-7:30之间进入车库多少车辆。
select count(*) from car_info
where
intime between
to_date('20120910 07:00:00','yyyymmdd hh24:mi:ss')
and
to_date('20120910 07:30:00','yyyymmdd hh24:mi:ss');

或者

select count(*)  from car_info 
where to_char(intime,'yyyymmdd hh24:mi:ss' ) 
between '20120910 07:00:00' 
and '20120910 07:30:00' ;
  1. 在7:30—8:00之间车库发生了事故,查找出所有的可疑车辆。
SELECT * FROM CAR_INFO
WHERE 
INTIME <=TO_DATE('2012-09-10 08:00:00','YYYY-MM-DD HH24:MI:SS') AND
OUTTIME>=TO_DATE('2012-09-10 07:30:00','YYYY-MM-DD HH24:MI:SS')
UNION
SELECT * FROM CAR_INFO
WHERE 
INTIME   <=TO_DATE('2012-09-10 08:00:00','YYYY-MM-DD HH24:MI:SS') AND
OUTTIME IS NULL;

或者

SELECT * FROM CAR_INFO
WHERE 
INTIME   <=TO_DATE('2012-09-10 08:00:00','YYYY-MM-DD HH24:MI:SS') AND
(OUTTIME>=TO_DATE('2012-09-10 07:30:00','YYYY-MM-DD HH24:MI:SS') OR
OUTTIME IS NULL);
  1. 求哪辆车停车时间最短,停了多久?
select * from (select carid ,(outtime-intime)*24  from car_info order by 2) where rownum<2 ;

4.按停车时间段建收费表,需求是:
0-5 10 //停车时间在0-5小时之间的 收费10元
5-10 9 //停车时间在5-10小时之间的 收费9元
10-20 7 //停车时间在10-20小时之间的 收费7元
20以上 5 //停车时间在20小时以上的 收费5元

注:如停车在时间段节点上按低费率计算,比如停车5小时收 9元,10小时收7元。
建立收费表:

--DROP TABLE FEE;
CREATE TABLE FEE(
MINTIME INT NOT NULL,
MAXTIME INT NOT NULL,
FEE INT NOT NULL);
INSERT INTO FEE VALUES(0,5,10);
INSERT INTO FEE VALUES(5,10,9);
INSERT INTO FEE VALUES(10,20,7);
INSERT INTO FEE VALUES(20,999999,5);
COMMIT;

5.按照FEE,求0-5,6-10,11-20,20以上各费率档次停了多少车,多少费用?

select mintime,maxtime,count(*),sum(ceil((OUTTIME-INTIME)*24)*fee)
from CAR_info,fee
where
ceil((OUTTIME-INTIME)*24) >=mintime and 
ceil((OUTTIME-INTIME)*24)
Oracle培训—案例整理_第4张图片
效果.png

3.导入千万数据(导数据、索引)

3.1 导入1千万条数据,数据存于 abc.txt

  • 用户system 创建表空间test_ts
CREATE TABLESPACE test_idx 
DATAFILE ' C:\oracle\oradata\ora9\test01.dbf ' size 1000M
DEFAULT STORAGE(
INITIAL 10k
NEXT 10k
PCTINCREASE 0);
  • 用户system 创建用户u01
CREATE USER u01 identified by a;
  • 用户system 无法创建会话,创建!
GRANT create session TO  u01;
  • 用户system 创建表权限
GRANT create table to u01;
  • 用户system 默认表空间test_ts;
ALTER USER u01 DEFAULT TABLESPACE test_ts;
  • 用户system 为u01创建表空间配额
ALTER USER u01 QUOTA UNLIMITED ON test_ts;
  • 用户u01创建表stu_info1
CREATE TABLE stu_info(
stu_info_id CHAR(10) NOT NULL,
stu_info_name VARCHAR2(30) NOT NULL,
stu_info_sex CHAR(1) NOT NULL,
stu_info_brithday date NOT NULL,
stu_info_card VARCHAR2(30),
stu_info_phone VARCHAR2(20),
stu_info_falldate date NOT NULL,
stu_info_class_id CHAR(10) NOT NULL);
  • 创建外部控制文件
LOAD DATA
INFILE "c:\abc.txt"
BADFILE "db.bad"
APPEND
INTO TABLE stu_info
( 
 stu_info_id position(1:10),
 stu_info_name position(12:23),
 stu_info_sex position(25:25),
 stu_info_brithday position(27:36) date "yyyy-mm-dd",
 stu_info_card position(38:55),
 stu_info_phone position(57:67),
 stu_info_falldate position(69:78) date "yyyy-mm-dd",
 stu_info_class_id position(80:89)
)
  • SQL*LOAD引导
sqlldr userid=u01/a control=db.ctl errors=1000 streamsize=104857600  log=abc.log

执行完后,检查是否导入成功:

Oracle培训—案例整理_第5张图片
效果.png

以下是abc.bad文件的输出数据:

Oracle培训—案例整理_第6张图片
(一).png
Oracle培训—案例整理_第7张图片
(二).png

3.2 给字段 stu_info_id 创建索引

create index stu_info1_id_idx on stu_info1(stu_info_id)  tablespace  test_idx;

如果表空间不足,可以增加表空间的大小。

alter  tablespace  test_idx  add  datafile 'C:\oracle\oradata\ora9\test02.dbf' size 1000M

4.多人聊天(权限、视图、函数)

4.1 多人使用自己的用户使用同一台主机

  1. 客户端打开 C:\oracle\ora92\network\admin 下面的 tnsnames.ora ,添加 share186
Oracle培训—案例整理_第8张图片
添加服务器.png

连接刚才的共享主机,在dos窗口下输入
C:>sqlplus scott/tiger@share186
这是使用scott用户登录,需求是使用自己的账号登陆,管理员需要为每个人建立自己的账户并且赋权限。
--创建角色
CREATE ROLE stu_role;
--角色挂用户
GRANT stu_role TO stu00;
GRANT stu_role TO stu01;
GRANT stu_role TO stu02;
GRANT stu_role TO stu03;
GRANT stu_role TO stu04;
GRANT stu_role TO stu05;
--授权
GRANT create session TO stu_role;
GRANT create any table TO stu_role;
--创建表空间
create tablespace stu_ts datafile 'c:\stu_ts.dbf' size 50m;
--默认表空间
ALTER USER stu00 default tablespace stu_ts;
ALTER USER stu01 default tablespace stu_ts;
ALTER USER stu02 default tablespace stu_ts;
ALTER USER stu03 default tablespace stu_ts;
ALTER USER stu04 default tablespace stu_ts;
ALTER USER stu05 default tablespace stu_ts;
--表空间配额给用户
ALTER USER stu00 QUOTA UNLIMITED ON stu_ts;
ALTER USER stu01 QUOTA UNLIMITED ON stu_ts;
ALTER USER stu02 QUOTA UNLIMITED ON stu_ts;
ALTER USER stu03 QUOTA UNLIMITED ON stu_ts;
ALTER USER stu04 QUOTA UNLIMITED ON stu_ts;
ALTER USER stu05 QUOTA UNLIMITED ON stu_ts;

4.2 stu00用户创建聊天的数据模型

--学生实体

CREATE TABLE chat_user(
id VARCHAR2(10) NOT NULL,
name VARCHAR2(20) NOT NULL,
sex INT NOT NULL); //1代表男生,0代表女生

-- 赋权限

GRANT SELECT,INSERT ,UPDATE ON chat_user TO STU_ROLE;

--聊天消息

CREATE TABLE message(
message VARCHAR2(100) NOT NULL, //内容
mdate DATE DEFAULT SYSDATE,  //时间取当前时间
aid VARCHAR2(10) NOT NULL,  //发消息者
bid VARCHAR2(10));   //收消息者

-- 赋权限

GRANT SELECT,INSERT ,UPDATE ON message TO STU_ROLE;

每个人使用自己的用户在 stu00用户的chat_user表里面插入自己的用户记录:
比如:老师执行的sql是: INSERT INTO stu00.chat_user VALUES('STU00','老师',1);
我学号是STU05,执行的sql是:INSERT INTO stu00.chat_user VALUES('STU05','gaoyx',0);
这样大家就可以通过插入 message语句来聊天了。

4.3 业务问题

1.查找最近5分钟我发给别人以及别人发给我的或者群发的消息,群发的bid是STU99。

select aid,bid,message,mdate from ms where aid='STU05' or  bid= in ('STU05','STU99')
and  mdate > = sysdate-5/(24*60) order by mdate desc;

2.根据2张表 chat_user、message,求出第一问,查询结果不可以用id来表示,要用聊天人的名字来表示。(视图)

CREATE
VIEW v_ms AS
SELECT to_char(mdate,'hh24:mi:ss') md,c1.name aname,c2.name bname,message 
from message ms,chat_user c1,chat_user c2
WHERE 
ms.aid=c1.id and ms.bid=c2.id and
(aid='STU00' OR bid in ('STU05','STU99'))
and MDATE >= sysdate-5/(24*60)
ORDER BY mdate DESC;

函数实现:

--自定义函数 y=f(x)
CREATE or REPLACE FUNCTION fn_abc(v_x in varchar2)
RETURN VARCHAR2
AS
v_name VARCHAR2(20);
BEGIN
     select name into v_name from chat_user where id=v_x;
     return v_name;
END;
SELECT to_char(mdate,'hh24:mi:ss'),fn_abc(aid),fn_abc(bid),message 
from message
WHERE 
(aid='STU00' OR bid in ('STU05','STU99'))
and MDATE >=sysdate-5/(24*60)
ORDER BY mdate DESC;

5.超市购物(存储过程)

5.1 多人连一台服务器,操作见4.1

5.2 stu00创建超时购物模型

--账户表

DROP TABLE BANK;
create table bank(
vipno char(5) not null primary key,
balance number(10,2) default 0)
TABLESPACE stu_ts;

--产品表

drop table product;
create table product(
pid char(10) not null primary key,
pname varchar(50) not null,
price number(10) not null,
amount number(10) default 0)
TABLESPACE stu_ts;

--对2张表进行同名定义

create public synonym bank for stu00.bank; 
create public synonym product for stu00.product;

--每个人(我是STU05)把自己的信息插入到 bank 表

insert into bank values("STU05","1000");

5.3 业务问题

1.stu00写存储过程插入product表数据

--创建新增商品存储过程
create or replace procedure ins_product(v_pid in char,v_name in varchar2,v_price in number,v_amount in number)
as 
begin
    insert into product values(v_pid,v_name,v_price,v_amount);
        commit;

end;
exec ins_product('STU00000001','笔 ',5,10);
create public synonym ins_product for stu00.ins_product;
grant execute any procedure to stu_role;

stu00用户创建了上面的存储过程并且给 stu_role分配权限,其他用户是不能使用这个存储过程的,会提示权限不足,必须给每个用户分配权限:grant execute any procedure to stu_05;

2.创建序列号,因为订单的流水号会用到

--创建序列号
create sequence sale_seq
INCREMENT BY 1 -- 每次加几个
START WITH 1 -- 从1开始计数
NOMAXVALUE -- 不设置最大值
NOCYCLE -- 一直累加,不循环
CACHE 10; 
create public synonym sale_seq for stu00.sale_seq

3.创建销售表并添加外键

drop table sale;
create table sale(
seqno varchar2(20) not null primary key,
vipno char(5) not null,
pid char(10) not null,
amount number(10) not null,
sdate date default sysdate
)TABLESPACE stu_ts;

create public synonym sale for stu00.sale;

alter table sale add constraint fk_vipno foreign key(vipno) references bank(vipno);
alter table sale add constraint fk_pid foreign key(pid) references product(pid);
  1. 写存储过程实现购物流程
    --主程序 pro_main
create or replace procedure pro_main(v_vipno in char,v_PId in char,v_Amount in number)
as
v_money number(10);
BEGIN
    v_money:=FN_price(v_PId)*v_Amount;
    PRO_BANK(v_vipno,v_money);
    up_product(v_PId,v_Amount);
    ins_sale(v_vipno,v_PId,v_Amount);
    commit;
    dbms_output.put_line('OK,购物成功!');
END;

create public synonym pro_main for stu00.pro_main;
create public synonym pro_bank for stu00.pro_bank;
create public synonym up_product for stu00.up_product;
create public synonym ins_sale for stu00.ins_sale;

注释:其实commit不应该在 分存储过程处理完提交的,而应该在每个分存储过程后面都要添加判断,每个子存储过程失败是要给一个返回码,主程序中判断如果等于失败的反馈码则 rollback,否则 commit

--查价格的函数 FN_price

create or replace function  FN_price(v_x  in char)
 return number
 as
 v_price number(10);
 begin
 select price  into v_price from  stu00.product  where pid=v_x;
 return v_price;
 end;

--转帐存储过程 PRO_BANK

CREATE OR REPLACE PROCEDURE PRO_BANK(
v_vipno in CHAR,
v_money in number)
as 
v_j NUMBER(10);
BEGIN
    select nvl(balance,0) into v_j from bank where vipno=v_vipno;
    if v_j>=v_money then
        update bank set balance=balance-v_money 
            where vipno=v_vipno;
        update bank set balance=balance+v_money 
            where vipno='STU20';
    else
        dbms_output.put_line('余额不足!');
        rollback;
    end if;
END;
/

--仓库存储过程 up_product

CREATE OR REPLACE PROCEDURE up_product(
v_pid in CHAR,v_amount in NUMBER)
AS
BEGIN
    update product set amount=amount-v_amount where pid=v_pid;
END;
/

--将购买记录写入sale表 ins_sale

create or replace procedure ins_sale(
v_vipno in char,
v_pid in char,
v_amount in number)
as
begin
    insert into sale values(
to_char(sysdate,'yyyymmddhh24miss')||Lpad(sale_seq.nextval,6,'000000'),
v_vipno,v_pid,v_amount,sysdate);
end;
/

--调用主存储过程完成订购:

exec pro_main('STU00','STU0600009',1);

5.测试并发

背景:11个人每个人准备20条调用购物存储过程的语句,大家同时买一个商品,即同一时间处理一个商品的220个订单。

执行结束后查看执行时间:select max(sdate)-min(sdate) from sale;
发现用了2S多,把主存储里面的打印 成功的信息注释掉再执行用时1S多,说明打印会耗时。

你可能感兴趣的:(Oracle培训—案例整理)