一、项目需求说明
二、项目代码
-- 用户表:用户ID,姓名,身份证,联系电话,联系地址
/*------------------------------------
1. 用户ID为主键 自增
2. 身份证号码唯一,15或18位
-------------------------------------*/
create table atm_user(
u_id int not null auto_increment,
u_name varchar(20) character set utf8 not null,
u_card_id varchar(18) not null,
u_phone varchar(11) not null,
u_address varchar(50) character set utf8,
primary key(u_id),
constraint u_card_id_unique unique(u_card_id)
);
-- drop trigger trg_tb_user_insert_check;
-- 创建触发器 身份证校验
create trigger trg_tb_user_insert_check before insert
on atm_user for each row
begin
declare msg varchar(100) character set utf8;
if new.u_card_id not regexp '[0-9]{18}|[0-9]{17}X|[0-9]{15}'
then
set msg = concat('用户身份证输入错误请重新输入');
signal sqlstate 'ERROR' set message_text = msg;
end if;
end;
/*
银行信息表:卡号,币种(人民币),存储类型(定期,活期,活定两便),开户时间,开户金额,当前账户金额,密码,是否挂失,储户ID
*/
create table bank_card_message(
card_id char(21) not null primary key,
card_currency varchar(20) default 'RMB' not null,
card_store_type enum('活期','定期','活定两便') character set utf8,
card_open_time timestamp not null default CURRENT_TIMESTAMP,
card_open_amount decimal(10,2) not null,
card_cur_balance decimal(10,2) default 0.00 not null,
card_password varchar(20) default '888888' not null,
card_if_loss enum('是','否') character set utf8 default '否',
u_id int not null,
constraint bc_u_fk foreign key(u_id) references atm_user(u_id) on delete cascade
);
-- drop trigger trg_tb_bank_insert_check;
-- 银行信息表约束触发器: 卡号,开户金额,密码
create trigger trg_tb_bank_insert_check before insert
on bank_card_message for each row
begin
declare b_msg varchar(100) character set utf8;
if new.card_id not regexp '^1010 3576 [0-9]{4} [0-9]{4}$'
then
set b_msg = concat('卡号输入错误请重新输入');
signal sqlstate 'ERROR' set message_text = b_msg;
elseif new.card_open_amount < 1
then
set b_msg = concat('开户金额必须大于1');
signal sqlstate 'ERROR' set message_text = b_msg;
elseif CHAR_LENGTH(new.card_password) < 6
then
set b_msg = concat('密码必须大于或等于6位');
signal sqlstate 'ERROR' set message_text = b_msg;
else
set new.card_cur_balance = new.card_open_amount; -- 设置当前余额为开户金额
end if;
end;
/*
交易信息表:交易日期,卡号,交易类型,交易金额,备注
*/
create table atm_tra_info(
card_id char(21) not null,
tr_type enum('存入','支取') character set utf8 default '存入',
tr_price decimal(10,2) not null,
tr_date timestamp not null default CURRENT_TIMESTAMP,
ty_remark varchar(100),
constraint tri_bc_fk foreign key(card_id) references bank_card_message(card_id) on delete cascade
);
-- drop trigger trg_tb_tri_insert_check;
-- 交易信息表触发器:交易金额
create trigger trg_tb_tri_insert_check before insert
on atm_tra_info for each row
begin
declare t_msg varchar(100) character set utf8;
set @oldloss = (select bank_card_message.card_if_loss from bank_card_message where bank_card_message.card_id = new.card_id limit 1);
set @oldprice = (select bank_card_message.card_cur_balance from bank_card_message where bank_card_message.card_id = new.card_id limit 1);
if @oldloss = '是'
then
set t_msg = concat('该银行卡已挂失无法进行交易');
signal sqlstate 'ERROR' set message_text = t_msg;
elseif new.tr_price <= 0
then
set t_msg = concat('交易金额必须大于0');
signal sqlstate 'ERROR' set message_text = t_msg;
-- 关联银行卡信息表存入支取操作触发器
elseif new.tr_type = '存入'
then
update bank_card_message set bank_card_message.card_cur_balance = new.tr_price+@oldprice where bank_card_message.card_id=new.card_id;
-- 只能发送错误的提示信号,所以无法提示恭喜
elseif new.tr_type = '支取'
then
if new.tr_price > @oldprice
then
set t_msg = concat('支取金额大于余额');
signal sqlstate 'ERROR' set message_text = t_msg;
elseif new.tr_price < @oldprice
then
update bank_card_message set bank_card_message.card_cur_balance = @oldprice-new.tr_price where bank_card_message.card_id=new.card_id;
end if;
end if;
end;
-- 删除触发器
-- drop trigger trg_tb_tri_update_check;
-- 创建触发器
create trigger trg_tb_tri_update_check before update
on atm_tra_info for each row
begin
declare p_msg varchar(100) character set utf8;
set @oldprice = (select bank_card_message.card_cur_balance from bank_card_message where bank_card_message.card_id = new.card_id limit 1);
set @oldlossif = (select bank_card_message.card_if_loss from bank_card_message where bank_card_message.card_id = new.card_id limit 1);
if @oldlossif = '是'
then
set p_msg = concat('该银行卡已挂失,无法进行操作');
signal sqlstate 'ERROR' set message_text = p_msg;
elseif new.tr_price <= 0
then
set p_msg = concat('交易金额必须大于0');
signal sqlstate 'ERROR' set message_text = p_msg;
end if;
-- 关联银行卡信息表存入支取修改操作触发器
if new.tr_type = old.tr_type
then
if new.tr_type = '存入'
then
update bank_card_message set bank_card_message.card_cur_balance = new.tr_price+@oldprice-old.tr_price where bank_card_message.card_id=new.card_id;
-- -- 只能发送错误的提示信号,所以无法提示恭喜
elseif new.tr_type = '支取'
then
if new.tr_price > @oldprice
then
set p_msg = concat('支取金额大于余额');
signal sqlstate 'ERROR' set message_text = p_msg;
elseif new.tr_price < @oldprice
then
update bank_card_message set bank_card_message.card_cur_balance = @oldprice-new.tr_price+old.tr_price where bank_card_message.card_id=new.card_id;
end if;
end if;
elseif new.tr_type <> old.tr_type
then
if new.tr_type = '存入'
then
update bank_card_message set bank_card_message.card_cur_balance = new.tr_price+@oldprice+old.tr_price where bank_card_message.card_id=new.card_id;
-- 只能发送错误的提示信号,所以无法提示恭喜
elseif new.tr_type = '支取'
then
if new.tr_price > @oldprice
then
set p_msg = concat('支取金额大于余额');
signal sqlstate 'ERROR' set message_text = p_msg;
elseif new.tr_price < @oldprice
then
update bank_card_message set bank_card_message.card_cur_balance = @oldprice-new.tr_price-old.tr_price where bank_card_message.card_id=new.card_id;
end if;
end if;
end if;
end;
-- 插入交易信息触发器 交易金额大于0测试
-- insert into atm_tra_info(card_id,tr_type,tr_price) values('1010 3576 4000 0001','存入',0);
-- 插入支取金额大于余额测试
-- insert into atm_tra_info(card_id,tr_type,tr_price) values('1010 3576 4000 0001','支取',10000);
-- 插入交易信息成功测试
-- insert into atm_tra_info(card_id,tr_type,tr_price) values('1010 3576 4000 0001','存入',100);
-- 更新金额为0触发器测试
-- update atm_tra_info set tr_price = 0 where card_id = '1010 3576 4000 0001';
-- 更新交易类型一样,金额修改测试
-- update atm_tra_info set tr_price = 200 where card_id = '1010 3576 4000 0001';
-- 更新改变交易类型测试
-- update atm_tra_info set tr_type = '支取' where card_id = '1010 3576 4000 0001';
-- 更新改变交易类型和金额
-- update atm_tra_info set tr_type = '存入',tr_price = 300 where card_id = '1010 3576 4000 0001';
-- 用户表测试
-- 身份证输入错误
-- insert into atm_user(u_name,u_card_id,u_phone,u_address) values('张三','123','10086','广东省深圳市');
-- 用户正确插入
-- insert into atm_user(u_name,u_card_id,u_phone,u_address) values('张三','350203200003074416','10086','广东省深圳市');
-- 用户身份证唯一
-- insert into atm_user(u_name,u_card_id,u_phone,u_address) values('李四','350203200003074416','10010','广东省深圳市');
-- 插入多个数据
-- insert into atm_user(u_name,u_card_id,u_phone,u_address) values('李四','110105200008025157','10010','北京市朝阳区');
-- insert into atm_user(u_name,u_card_id,u_phone,u_address) values('郭通','120101199707139648','10000','天津市和平区');
-- insert into atm_user(u_name,u_card_id,u_phone,u_address) values('王五','210281200309195489','15650565566','辽宁省大连市');
-- insert into atm_user(u_name,u_card_id,u_phone,u_address) values('刘六','31011220050108037X','13866688855','上海市闵行区');
--
-- 银行卡信息表
-- 卡号输入错误
-- insert into bank_card_message(card_id,card_store_type,card_open_amount,card_password,u_id) values('123','活期','1000.00','123456','1');
-- 开户金额错误
-- insert into bank_card_message(card_id,card_store_type,card_open_amount,card_password,u_id) values('1010 3576 4000 0000','活期','0.00','654321','2');
-- 密码格式错误
-- insert into bank_card_message(card_id,card_store_type,card_open_amount,card_password,u_id) values('1010 3576 4000 0001','活期','100.00','1','1');
-- 活期定期,是否选择输入
-- insert into bank_card_message(card_id,card_store_type,card_open_amount,card_password,u_id) values('1010 3576 4000 0002','活期吧','1000.00','123123','1');
-- insert into bank_card_message(card_id,card_store_type,card_open_amount,card_password,card_if_loss,u_id) values('1010 3576 4000 0002','活期','1000.00','123123','不知道','1');
-- 正确插入
-- insert into bank_card_message(card_id,card_store_type,card_open_amount,card_password,u_id) values('1010 3576 4000 0001','活期','1000.00','123456','1');
-- insert into bank_card_message(card_id,card_store_type,card_open_amount,card_password,u_id) values('1010 3576 4000 0002','活期','2000.00','654321','2');
-- insert into bank_card_message(card_id,card_store_type,card_open_amount,card_password,u_id) values('1010 3576 4000 0003','活期','3000.00','159357','1');
-- insert into bank_card_message(card_id,card_store_type,card_open_amount,u_id) values('1010 3576 4000 0004','活期','1200.00','4');
-- insert into bank_card_message(card_id,card_store_type,card_open_amount,card_password,u_id) values('1010 3576 4000 0005','活期','5000.00','666666','5');
-- insert into bank_card_message(card_id,card_store_type,card_open_amount,card_password,u_id) values('1010 3576 4000 0006','活期','6000.00','789456','6');
-- 创建储户表视图
create or replace view atm_user_view as select * from atm_user;
-- 测试
-- select * from atm_user_view;
--
-- 创建银行卡信息表视图
create or replace view bc_view as select * from bank_card_message;
-- 测试
-- select * from bc_view;
-- 创建交易信息表视图
create or replace view tra_info_view as select * from atm_tra_info;
-- 测试
-- select * from tra_info_view;
-- 创建查询挂失的客户信息视图
create or replace view rep_loss_view as select atm_user.*,bank_card_message.card_id,bank_card_message.card_cur_balance from bank_card_message,atm_user where bank_card_message.card_if_loss='是' and bank_card_message.u_id=atm_user.u_id;
-- 测试
-- select * from rep_loss_view;
-- 创建查询本周开户的卡号显示相关信息视图
create or replace view bc_tweek_view as select * from bank_card_message where YEARWEEK(date_format(card_open_time,'%Y-%m-%d')) = YEARWEEK(now());
-- 测试
-- select * from bc_tweek_view;
-- 创建查询本月交易金额最高的卡号的视图
create or replace view bc_mmax_atm as
select distinct card_id from atm_tra_info
where tr_price = (
select max(tr_price) from atm_tra_info
where month(now())
);
-- 测试
-- select * from bc_mmax_atm;
-- 不允许修改卡号触发器
create trigger atm_bc_update_id
before update on bank_card_message for each row
begin
declare u_msg varchar(100) character set utf8;
set @oldprice = (select bank_card_message.card_cur_balance from bank_card_message where bank_card_message.card_id = new.card_id limit 1);
set @olddate = (select atm_tra_info.tr_date from atm_tra_info where atm_tra_info.card_id = new.card_id limit 1);
set @oldlossup = (select bank_card_message.card_if_loss from bank_card_message where bank_card_message.card_id = new.card_id limit 1);
if @oldlossup = '是'
then
set u_msg = concat('该卡号已经挂失,无法进行修改操作');
signal sqlstate 'ERROR' set message_text = u_msg;
elseif new.card_id <> old.card_id
then
set u_msg = concat('此列不允许修改');
signal sqlstate 'ERROR' set message_text = u_msg;
end if;
end;
-- 不允许修改卡号测试
-- update bank_card_message set card_id = 500 where u_id = 1;
-- drop trigger atm_bc_update_id;
-- 创建函数,卡号随机生成
create FUNCTION get_user_card_id() returns varchar(21)
begin
declare card_id varchar(21) default '';
set card_id = concat('1010 3576 ',ROUND(rand()*10000));
set card_id = concat(card_id,' ');
set card_id = concat(card_id,ROUND(rand()*10000));
return card_id;
end;
-- 开户的存储过程
-- drop procedure open_bank_atm;
create procedure open_bank_atm(in
user_name varchar(20) character set utf8, -- 开户姓名
user_card_id varchar(18), -- 用户身份证号码
user_phone varchar(11), -- 用户电话
user_address varchar(50) character set utf8, -- 用户地址
card_sto_type varchar(10) character set utf8, -- 存储类型
card_open_price decimal(10,2), -- 金额
card_psw varchar(20) -- 密码
)
begin
declare the_user_id_check varchar(18);
declare num int;
-- 根据身份证判断此用户是否存在
select count(u_card_id) into num from atm_user where atm_user.u_card_id = user_card_id;
if num = 0
then
-- 没有这个用户名,在用户信息表加入这个用户信息
insert into atm_user(u_name,u_card_id,u_phone,u_address) values(user_name,user_card_id,user_phone,user_address);
else
-- 有此用户,此用户开多个表
select u_id into the_user_id_check from atm_user where atm_user.u_card_id = user_card_id limit 1;
end if;
-- 插入到银行信息表
insert into bank_card_message(card_id,card_store_type,card_open_amount,card_password,u_id) values(get_user_card_id(),card_sto_type,card_open_price,card_psw,the_user_id_check);
commit;
end;
-- 测试开户存储过程
-- call open_bank_atm('张三','350203200003074416','18080456123','福建省福州市','活期',1000,'663366');
-- call open_bank_atm('张三','350203200003074416','10086','福建省厦门市','定期',2000,'868686');
-- call open_bank_atm('李四','350982200601060130','1000011','上海市闵行区','随便',3000,'111555');
-- 创建修改密码的存储过程
create procedure update_card_psw(in
the_up_u_card_id varchar(21), -- 要修改的银行卡
new_card_psw varchar(20) -- 新密码
)
begin
declare num int;
declare p_ucard_message varchar(100) character set utf8;
-- 根据银行卡号判断此卡是否存在
select count(card_id) into num from bank_card_message where bank_card_message.card_id = the_up_u_card_id;
if num = 0
then
-- 没有这个银行卡,警报
set p_ucard_message = concat('此卡号不存在,请重新尝试!');
signal sqlstate 'ERROR' set message_text = p_ucard_message;
else
-- 有此卡号,进行修改操作
update bank_card_message set card_password = new_card_psw where bank_card_message.card_id = the_up_u_card_id;
end if;
commit;
end;
-- 修改密码测试
-- 卡号存在
-- call update_card_psw('1010 3576 9767 2679','1008611');
-- 卡号不存在
-- call update_card_psw('1010 3576 9767 1111','123456');
-- 创建挂失账号的存储过程
create procedure go_loss_id(in
the_loss_card_id varchar(21) -- 要挂失的银行卡号
)
begin
declare num int;
declare p_goloss_message varchar(100) character set utf8;
-- 根据卡号判断此卡是否存在
select count(card_id) into num from bank_card_message where bank_card_message.card_id = the_loss_card_id;
if num = 0
then
-- 没有这个银行卡,警报
set p_goloss_message = concat('此卡号不存在,请重新尝试');
signal sqlstate 'ERROR' set message_text = p_goloss_message;
else
-- 卡号存在,进行挂失操作
update bank_card_message set card_if_loss = '是' where bank_card_message.card_id = the_loss_card_id;
end if;
commit;
end;
-- 卡号挂失测试
-- 卡号存在
-- call go_loss_id('1010 3576 9767 2679');
-- 卡号不存在
-- call go_loss_id('1010 3576 9767 1234');
-- 支取和存入的存储过程
create procedure in_out_tri(in
the_tr_card_id varchar(21), -- 卡号
the_tr_type varchar(12) character set utf8, -- 交易类型
the_tr_price decimal(10,2) -- 交易金额
)
begin
declare num int;
declare p_gotr_message varchar(100) character set utf8;
-- 根据卡号判断此卡是否存在
select count(card_id) into num from bank_card_message where bank_card_message.card_id = the_tr_card_id;
if num = 0
then
-- 没有这个银行卡,警报
set p_gotr_message = concat('此卡号不存在,请重新尝试');
signal sqlstate 'ERROR' set message_text = p_gotr_message;
else
-- 卡号存在,进行交易操作
insert into atm_tra_info(card_id,tr_type,tr_price) values(the_tr_card_id,the_tr_type,the_tr_price);
end if;
commit;
end;
-- 交易支取和存入测试
-- 支取金额大于余额
-- call in_out_tri('1010 3576 9767 2679','支取',30000);
-- 存入金额为0
-- call in_out_tri('1010 3576 4000 0001','存入',0);
-- 正确存入
-- call in_out_tri('1010 3576 4000 0001','存入',100);
-- 正确支取
-- call in_out_tri('1010 3576 4000 0003','支取',200);
-- 创建查询余额存储过程
create procedure check_balance(in
the_check_ba_card_id varchar(21), -- 查询余额的卡号
the_check_ba_card_psw varchar(20) -- 查询余额的密码
)
begin
declare num int;
declare psw varchar(20);
declare p_check_message varchar(100) character set utf8;
-- 根据卡号判断此卡是否存在
select count(card_id) into num from bank_card_message where bank_card_message.card_id = the_check_ba_card_id;
if num = 0
then
-- 没有这个银行卡,警报
set p_check_message = concat('此卡号不存在,请重新尝试');
signal sqlstate 'ERROR' set message_text = p_check_message;
else
-- 卡号存在,进行查询操作
select card_password into psw from bank_card_message where bank_card_message.card_id = the_check_ba_card_id;
if the_check_ba_card_psw = psw
then
select card_cur_balance from bank_card_message where bank_card_message.card_id = the_check_ba_card_id;
else
-- 密码错误,警报
set p_check_message = concat('输入的银行卡密码错误,请重新尝试!');
signal sqlstate 'ERROR' set message_text = p_check_message;
end if;
end if;
commit;
end;
-- 查询余额测试
-- call check_balance('1010 3576 4000 0001','654321');
-- call check_balance('1010 3576 4000 0001','123456');
-- 创建转账存储过程
create procedure do_transf(in
the_out_card_id varchar(21), -- 转出账号
the_in_card_id varchar(21), -- 转入账号
the_tran_price decimal(10,2) -- 转账金额
)
begin
declare out_num int; -- 转出账号是否存在
declare in_num int; -- 转入账号是否存在
declare out_price decimal(10,1); -- 转出账号余额
declare p_tran_message varchar(100) character set utf8;
set @outoldprice = (select bank_card_message.card_cur_balance from bank_card_message where bank_card_message.card_id = the_out_card_id limit 1);
set @inoldprice = (select bank_card_message.card_cur_balance from bank_card_message where bank_card_message.card_id = the_in_card_id limit 1);
-- 根据卡号判断此卡是否存在
select count(card_id) into out_num from bank_card_message where bank_card_message.card_id = the_out_card_id;
select count(card_id) into in_num from bank_card_message where bank_card_message.card_id = the_in_card_id;
if out_num = 0 || in_num = 0
then
-- 没有这个银行卡,警报
set p_tran_message = concat('卡号不存在,请重新尝试');
signal sqlstate 'ERROR' set message_text = p_tran_message;
else
-- 卡号存在,进行转账操作
select card_cur_balance into out_price from bank_card_message where bank_card_message.card_id = the_out_card_id;
if the_tran_price > out_price
then
set p_tran_message = concat('交易金额大于余额,交易失败');
signal sqlstate 'ERROR' set message_text = p_tran_message;
else
-- 转账操作
update bank_card_message set card_cur_balance = @outoldprice-the_tran_price where bank_card_message.card_id = the_out_card_id;
update bank_card_message set card_cur_balance = @inoldprice+the_tran_price where bank_card_message.card_id = the_in_card_id;
end if;
end if;
commit;
end;
-- 转账测试
-- call do_transf('1010 3576 4000 0001','1010 3576 4000 0000',100.00);
-- call do_transf('1010 3576 4000 0004','1010 3576 4000 0002',10000);
-- call do_transf('1010 3576 4000 0001','1010 3576 4000 0002',100.00);
-- 创建销户存储过程
create procedure del_user(in
the_del_user_id varchar(18) -- 要删除的用户身份证
)
begin
declare tmp int default 0;
declare sum int default 0;
declare done int default -1;
declare u_num int; -- 身份证是否存在
declare id_num int; -- u_id
declare check_card_id varchar(21); -- 游标投入的银行卡号
declare d_check_message varchar(100) character set utf8;
declare cursor_card_id cursor for select bank_card_message.card_id from bank_card_message; -- 游标遍历该用户的所有银行卡
declare continue handler for not found set done = 1;
select atm_user.u_id into id_num from atm_user where atm_user.u_card_id = the_del_user_id limit 1; -- 得到用户自增u_id
-- 根据身份证判断此卡是否存在
select count(u_id) into u_num from atm_user where atm_user.u_card_id = the_del_user_id;
if u_num = 0
then
-- 没有这个用户,警报
set d_check_message = concat('此用户不存在,请重新尝试');
signal sqlstate 'ERROR' set message_text = d_check_message;
else
-- 身份证存在,进行销户操作
open cursor_card_id; -- 打开游标
posloop:LOOP
if done=1 then
leave posloop;
end if;
fetch cursor_card_id into check_card_id;
delete from atm_tra_info where atm_tra_info.card_id = check_card_id; -- 删除交易信息表
delete from bank_card_message where bank_card_message.u_id = id_num; -- 删除银行信息表
end loop posloop;
close cursor_card_id;
delete from atm_user where atm_user.u_card_id = the_del_user_id; -- 删除用户信息表
end if;
end;
-- 销户测试
-- call del_user('350203200003074416');