-- --------------------------------------------------userinfo表、用户表
-- 1.1 创建userinfo表--
create table UserInfo(
customerID int primary key,
customerName varchar(10) not null,
personID varchar(20) not null unique,
telephone varchar(20) not null,
address varchar(30)
);
-- 1.2 为身份证号和电话增加正则表达式约束--
alter table userinfo add constraint CK_TELEPHONE
check(regexp_like(telephone,'^1[3,4,5,7,8][0-9]-[0-9]{8}$|^[0-9]{3,4}-[0-9]{8}$'));
alter table userinfo add constraint CK_PERSONID
check(regexp_like(personid,'^[0-9]{15}$|^[0-9]{17}[0-9,x]$'));
-- 1.3向userinfo表中插入3条记录
insert into userinfo(customerName,personID,telephone,address) values
('李四','370404066601022222','15000000111','山东济宁'),
('王五','370404066601023333','15000000222','山东枣庄'),
('赵六','370404066601024444','15000000111','山东菏泽'),
('祁七','370404066601025555','15000000222','山东泰安')
-- 1.4 客户信息表视图
create or replace VIEW vw_userInfo
AS
select customerID as 客户编号,customerName as 开户名, personID as 身份证号,
telephone as 电话号码,address as 居住地址 from userInfo;
-- 1.5查询挂失帐号的客户信息
SELECT * FROM vw_cardInfo;
SELECT customerName as 客户姓名,telephone as 联系电话 FROM userInfo WHERE customerID IN (SELECT customerID FROM cardInfo WHERE IsReportLoss=1);
-- --------------------------------------------------------cardinfo表、银行卡
-- 2.1 创建cardinfo表--
create table CardInfo(
cardID varchar(30) primary key,
curID varchar(5) default 'RMB' not null,
savingID varchar(5) not null,
openDate DATE NOT NULL,
openMoney decimal(10,2) not null check(openMoney>=1),
balance decimal(10,2) not null check(balance>=1),
pwd varchar(10) default '888888' not null ,
IsReportLoss char(2) default '否' not null,
customerID int not null references UserInfo(customerID)
);
-- 2.2 为卡号和密码增加正则表达式约束--
alter table cardinfo add constraint CK_PWD check
(regexp_like(pwd,'^[0-9]{6}$'));
alter table cardinfo add constraint CK_CARDID check
(regexp_like(cardid,'^1010[[:space:]]3576[[:space:]][0-9]{4}[[:space:]][0-9]{4}$'));
-- 2.3 向cardinfo表中插入3条记录
insert into cardinfo(cardID,savingID,openMoney,balance,pwd,customerID) values
('1010 3576 0000 0000','活期',10,2,'000000',1),
('1010 3576 0000 0001','活期',100,20,'000001',2),
('1010 3576 0000 0010','活期',1000,200,'000010',3),
('1010 3576 0000 0011','活期',10000,2000,'000011',4),
('1010 3576 0000 0012','活期',10000,20,'000100',5)
-- 2.4 银行卡信息表视图
create or replace VIEW vw_cardInfo
AS
select c.cardID as 卡号,u.customerName as 客户,c.curID as 货币种类,c.openMoney as 存取金额,
c.balance as 余额,c.pwd 密码,
case c.IsReportLoss when 0 then '正常'
when 1 then '挂失'
end as 是否挂失
from cardInfo c, userinfo u
where c.customerID=u.customerID;
-- 2.5修改密码
-- 1.张三(卡号为1010 3576 0000 0000)修改银行卡密码为123456
-- 2.李四(卡号为1010 3576 0000 0001)修改银行卡密码为123123
update cardInfo set pwd='123456' WHERE cardID='1010 3576 0000 0000' ;
update cardInfo set pwd='123123' WHERE cardID='1010 3576 0000 0001' ;
-- 查询账户信息
SELECT * FROM vw_cardInfo;
-- (2)注销账户
delete from cardInfo where cardID='1010 3576 0000 0000'
-- (3)挂失帐号。李四(卡号为22222)因银行卡丢失,申请挂失
update cardInfo set IsReportLoss=1 WHERE cardID='1010 3576 0000 0001' ;
SELECT * FROM vw_cardInfo;
-- 查看修改密码和挂失结果
SELECT cardid 卡号,curID 货币,opendate 开户日期,openmoney 开户金额,balance 余额,pwd 密码,
case IsReportLoss WHEN 1 THEN '挂失' WHEN 0 THEN '未挂失' ELSE NULL end 是否挂失,
customerName 客户姓名
FROM CardInfo, UserInfo
WHERE CardInfo.customerID = UserInfo.customerID;
-- (4)查询本周开户的卡号,显示该卡相关信息
SELECT c.cardID 卡号,u.customerName 姓名,c.curID 货币,c.openDate 开户日期,c.openMoney 开户金额,c.balance 存款余额,
CASE c.IsReportLoss WHEN 0 THEN '正常账户'
WHEN 1 THEN '挂失账户'
ELSE NULL
END 账户状态
FROM cardInfo c INNER JOIN userInfo u ON (c.customerID = u.customerID)
WHERE openDate between trunc(sysdate,'DAY') and trunc(sysdate,'DAY')+6;
-- (5)、按银行卡余额降序创建索引。
create index money_desc_index on cardInfo(balance desc);
show index from cardInfo;
-- ------------------------------------------------------tradeinfo表、交易表
-- 3.1 创建tradeinfo表
create table TradeInfo(
tradeDate DATE NOT NULL,
cardID varchar(30) not null references CardInfo(cardID),
transType varchar(10) not null,
transMoney decimal(10,2) not null,
remark varchar(50)
);
-- 3.2 为transtype增加约束--
alter table tradeinfo add constraint CK_TRANSTYPE check (transtype in('支取','存入'));
-- 3.3 向transinfo表中插入3条记录
insert into tradeinfo(cardID,transType,transMoney) values
('1010 3576 0000 0000','存入',100),
('1010 3576 0000 0001','存入',100),
('1010 3576 0000 0000','存入',100),
('1010 3576 0000 0001','存入',100),
('1010 3576 0000 0010','支取',100)
-- 3.4 创建视图:查看交易信息
create VIEW vw_tradeInfo
AS
select tradeDate as 交易日期, cardID as 卡号, transType as 交易类型,transMoney as 交易金额,
remark as 备注 from tradeInfo ;
-- 3.5查询本月交易金额最高的卡号
SELECT DISTINCT cardID FROM TradeInfo
WHERE transMoney=(SELECT MAX(transMoney) FROM TradeInfo);
-- ------------------------------------创建存储过程通过随机数产生卡号(未成功)-------------------------
create proc randomcardid
@cardid char(19)output
as
select @cardid='1010 3576 '+substring(convert(char(10),RAND()*10000),0,5)+' '+substring(convert(char(10),RAND()*10000),0,5)
-- -----------------------------------------------------------------DML(未成功)
create or replace procedure usp_randCardID(v_randCardID OUT char)
AS
v_r number(5);
BEGIN
v_r:='1010 3576 0000 '+round(dbms_random.value(1000,9999));
v_randCardID:=substr(v_r,1,4);
end;
-- <2>开户的存储过程
CREATE SEQUENCE seq_customerID
START WITH 10
INCREMENT BY 1
NOMAXVALUE
NOCYCLE
CACHE 30;
create or replace
procedure usp_openAccount
( v_customerName varchar,
v_PID varchar,
v_telephone varchar,
v_openMoney number,
v_savingID number,
v_address varchar default '' )
AS
v_mycardID char(19);
v_cur_customerID int;
v1 int;
begin
-- ---------------------------------------------------------
#生成N个随机数字函数
CREATE FUNCTION usp_randCardID(N int) RETURNS VARCHAR(255)
begin
# 定义一个默认获取的值0-9
DECLARE chars_str varchar(20) DEFAULT '0123456789';
#将随机获取后得值保存在 return_str
DECLARE return_str varchar(255) DEFAULT '';
# 定义一个变量用来判断循环的参次数
DECLARE i INT DEFAULT 0;
WHILE i < n
DO
# 使用随机函数将 chars_str随机获取一个数字进行累加
SET return_str = concat(return_str, substring(chars_str, FLOOR(1 + RAND() * 10), 1));
#变量加1
SET i = i + 1;
END WHILE;
#最终结果返回
RETURN return_str;
END
-- ----------------------调用产生随机卡号的存储过程获得随机卡号
usp_randCardID (v_mycardID);
SELECT count(*) into v1 FROM cardInfo WHERE cardID=v_mycardID;
while (v1<>0) loop
usp_randCardID (v_mycardID);
SELECT count(*) into v1 FROM cardInfo WHERE cardID=v_mycardID;
end loop;
dbms_output.put_line('尊敬的客户,开户成功!系统为您产生的随机卡号为:'||v_mycardID);
dbms_output.put_line('开户日期'||to_char(sysdate,'yyyy-mm-dd')||' 开户金额:'||to_char(v_openMoney));
select count(*) into v1 from userInfo where PID=v_PID;
dbms_output.put_line('v1='|| to_char(v1));
if v1 = 0 then
INSERT INTO userInfo(customerID,customerName,PID,telephone,address) VALUES(seq_customerID.nextval,v_customerName,v_PID,v_telephone,v_address);
end if;
select customerID into v_cur_customerID from userInfo where PID=v_PID;
INSERT INTO cardInfo(cardID,savingID,openMoney,balance,customerID)
VALUES(v_mycardID,v_savingID,v_openMoney,v_openMoney,v_cur_customerID);
exception
when no_data_found then
raise_application_error(-20000,'开户失败,请重新输入!');
when others then
raise_application_error(-20001,'其他错误,请重新输入!');
end;
-- <2>开户的存储过程---------------------------------------------------------
CREATE SEQUENCE seq_customerID
START WITH 10
INCREMENT BY 1
NOMAXVALUE
NOCYCLE
CACHE 30;
create or replace
procedure usp_openAccount
( v_customerName varchar,
v_PID varchar,
v_telephone varchar,
v_openMoney number,
v_savingID number,
v_address varchar default '' )
AS
v_mycardID char(19);
v_cur_customerID int;
v1 int;
begin
--调用产生随机卡号的存储过程获得随机卡号
usp_randCardID (v_mycardID);
SELECT count(*) into v1 FROM cardInfo WHERE cardID=v_mycardID;
while (v1<>0) loop
usp_randCardID (v_mycardID);
SELECT count(*) into v1 FROM cardInfo WHERE cardID=v_mycardID;
end loop;
dbms_output.put_line('尊敬的客户,开户成功!系统为您产生的随机卡号为:'||v_mycardID);
dbms_output.put_line('开户日期'||to_char(sysdate,'yyyy-mm-dd')||' 开户金额:'||to_char(v_openMoney));
select count(*) into v1 from userInfo where PID=v_PID;
dbms_output.put_line('v1='|| to_char(v1));
if v1 = 0 then
INSERT INTO userInfo(customerID,customerName,PID,telephone,address) VALUES(seq_customerID.nextval,v_customerName,v_PID,v_telephone,v_address);
end if;
select customerID into v_cur_customerID from userInfo where PID=v_PID;
INSERT INTO cardInfo(cardID,savingID,openMoney,balance,customerID)
VALUES(v_mycardID,v_savingID,v_openMoney,v_openMoney,v_cur_customerID);
exception
when no_data_found then
raise_application_error(-20000,'开户失败,请重新输入!');
when others then
raise_application_error(-20001,'其他错误,请重新输入!');
end;
-- 调用存储过程开户-------------------------------------------------------------------------------------------------------
begin
usp_openAccount ('老五','334456889012678000','010-44433572',1000,1,'河南');
commit;
end;
-- 2. 修改某个账户密码的存储过程-------------------------------------------
-- <1>修改密码的存储过程
create or replace
procedure usp_updatePass
(v_card char, --卡号
v_newPass char,
v_inputPass char default NULL) --密码
as
v_myPass char(6);--原密码
begin
SELECT pass into v_myPass FROM cardInfo WHERE cardID=v_card and pass=v_inputPass;
if (v_myPass=v_inputPass) then
update cardInfo set pass=v_newPass WHERE cardID=v_card;
dbms_output.put_line('修改成功!');
else
dbms_output.put_line('原密码输入有误!');
raise_application_error(-20000,'密码输入错误!');
end if;
commit;
exception
when no_data_found then
raise_application_error(-20001,'卡号或密码错误!');
end;
-- <2>调用修改密码的存储过程
begin
usp_updatePass ('52315','123456','888888');
commit;
end;
-- 4. 创建转帐事务存储过程
-- <1>创建取钱或存钱的存储过程
create or replace procedure usp_takeMoney
(v_card char, --卡号
v_m number, --存取金额
v_type char, --存取类型
v_inputPass char default NULL) --密码
as
v1 number(1); --临时变量
v_mybalance number; --余额
begin
dbms_output.put_line('交易正进行,请稍后......');
if (v_type='支取') then
SELECT 1 into v1 FROM cardInfo WHERE cardID=v_card and pass=v_inputPass;
end if;
SELECT balance into v_mybalance
FROM cardInfo
WHERE cardID=v_card;
if (v_type='支取') then
if (v_mybalance>=v_m+1) then
update cardInfo set balance=balance-v_m WHERE cardID=v_Card;
else
dbms_output.put_line('卡号'||v_card||' 余额:'||to_char(v_mybalance));
raise_application_error(-20000,'交易失败!余额不足!');
end if;
else
update cardInfo set balance=balance+v_m WHERE cardID=v_card;
end if;
dbms_output.put_line('交易成功!交易金额:'||to_char(v_m));
SELECT balance into v_mybalance FROM cardInfo WHERE cardID=v_card;
dbms_output.put_line('卡号'||v_card||' 余额:'||to_char(v_mybalance));
INSERT INTO tradeInfo(tradeType,cardID,tradeMoney) VALUES(v_type,v_card,v_m);
commit;
exception
when no_data_found then
raise_application_error(-20001,'卡号或密码错误!');
end;
-- <2>创建打印对账单的存储过程
CREATE OR REPLACE PROCEDURE usp_CheckSheet(
v_cardID varchar2,
v_date1 date:=NULL,
v_date2 date:=NULL)
AS
v_custName varchar2(20);
v_curName varchar2(20);
v_openDate date;
TYPE cursor_type IS REF CURSOR;
--声明一个游标变量
c1 CURSOR_TYPE;
v_trade tradeinfo%rowtype;
v_sqlStr varchar2(2000);
BEGIN
SELECT c.curID, u.customerName ,c.openDate
INTO v_curName,v_custName, v_openDate FROM cardInfo c inner join userInfo u on c.customerID=u.customerID WHERE cardID = v_cardID;
dbms_output.put_line('卡号:' || v_cardID);
dbms_output.put_line('姓名:' || v_custName);
dbms_output.put_line('货币:' || v_curName);
dbms_output.put_line('开户日期:' || to_char(v_openDate,'yyyy"年"mm"月"dd"日"'));
dbms_output.put_line(' ');
dbms_output.put_line('--------------------------------------------------------------------');
dbms_output.put_line('交易日 '||' 类型 '||' 交易金额 '||' 备注');
v_sqlStr:='SELECT * FROM tradeInfo WHERE cardID='''||v_cardID||'''';
IF v_date2 IS NOT NULL THEN
v_sqlStr:=v_sqlStr||' AND tradeDate <=to_date('''||to_char(v_date2,'yyyy-mm-dd')||' 23:59:59'||''',''yyyy-mm-dd hh24:mi:ss'')';
END IF;
IF v_date1 IS NOT NULL THEN
v_sqlStr:=v_sqlStr||' AND tradeDate >=to_date('''||to_char(v_date1,'yyyy-mm-dd')||' 00:00:00'||''',''yyyy-mm-dd hh24:mi:ss'')';
END IF;
v_sqlStr:=v_sqlStr||' ORDER BY tradeDate';
--dbms_output.put_line(v_sqlStr);
open c1 for v_sqlStr;
LOOP
FETCH c1 INTO v_trade ;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(to_char(v_trade.tradeDate,'yyyy-mm-dd')||' '||v_trade.tradeType||' '||v_trade.tradeMoney||' '||v_trade.remark);
END LOOP;
CLOSE c1;
END;
-- <3>转帐的事务存储过程
create or replace procedure usp_tradefer (
v_card1 varchar2,
v_pwd varchar2,
v_card2 varchar2,
v_outmoney number)
AS
v_date1 date:= sysdate;
v_date2 date:= sysdate;
emp_20000 EXCEPTION;
PRAGMA EXCEPTION_INIT(emp_20000, -20000);
emp_20001 EXCEPTION;
PRAGMA EXCEPTION_INIT(emp_20001, -20001);
BEGIN
commit;
dbms_output.put_line('开始转账,请稍后......');
usp_takeMoney(v_card1,v_outmoney ,'支取',v_pwd);
usp_takeMoney(v_card2,v_outmoney ,'存入');
commit;
dbms_output.put_line('转账成功!');
v_date2 := sysdate;
dbms_output.put_line('打印转出账户对账单');
dbms_output.put_line('-------------------');
usp_CheckSheet(v_card1,v_date1,v_date2);
dbms_output.put_line('打印转入账户对账单');
dbms_output.put_line( '-------------------');
usp_CheckSheet(v_card2,v_date1,v_date2);
EXCEPTION
WHEN emp_20000 THEN
DBMS_OUTPUT.PUT_LINE('交易失败!余额不足!转账失败!');
rollback;
WHEN emp_20001 THEN
DBMS_OUTPUT.PUT_LINE('卡号或密码错误! 转账失败!');
rollback;
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('出现了其他异常错误,转账失败!');
rollback;
END;
-- <4>测试上述事务存储过程
-- 从李四的帐户转帐2000到张三的帐户
DECLARE
emp_20000 EXCEPTION;
PRAGMA EXCEPTION_INIT(emp_20000, -20000);
emp_20001 EXCEPTION;
PRAGMA EXCEPTION_INIT(emp_20001, -20001);
v_card1 char(19);
v_card2 char(19);
BEGIN
select cardID into v_card1
from cardInfo Inner Join userInfo ON cardInfo.customerID=userInfo.customerID
where customerName='李四';
select cardID into v_card2
from cardInfo Inner Join userInfo ON cardInfo.customerID=userInfo.customerID
where customerName='张三';
usp_tradefer(v_card1,'123123',v_card2,2000);
EXCEPTION
WHEN emp_20000 THEN
DBMS_OUTPUT.PUT_LINE('交易失败!余额不足!转账失败!');
WHEN emp_20001 THEN
DBMS_OUTPUT.PUT_LINE('密码错误!转账失败!');
WHEN no_data_found THEN
DBMS_OUTPUT.PUT_LINE('用户名不存在!转账失败!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('出现了其他异常错误!');
END;
-- 1. 交易信息表中的交易日期不允许修改。
create or replace
TRIGGER tri_updataDate
before update ON tradeinfo
FOR EACH ROW
BEGIN
if updating('tradedate') then
raise_application_error(-20000,'不能更新交易时间字段');
end if;
END;
-- 2. 测试触发器。
update tradeinfo set tradedate='22-6月-20'