Oracle校园卡消费系统(文档+代码)

目录

 

1 系统分析

1.1 题目要求

1.2 题目分析

2 数据库设计与实现

2.1 概念结构设计

2.2 物理结构设计

3 数据库实施

3.1 建立数据表、索引、序列,视图

3.2 插入初始数据

3.3 设计pl存储过程

4 其它说明

4.1 遇到的问题

4.2 代码


1 系统分析

1.1 题目要求

校园卡可以用于食堂就餐和商铺消费结算。每个食堂消费终端内置有唯一的终端编号,结算时先输入金额,顾客再刷卡,系统自动从卡中扣除相应金额。每个商铺销售终端都有唯一编号,消费时需要输入各商品编号、数量,系统从数据库中读出单价并计算消费总额。每周由财务处进行一次集中结算,统计每个商铺和食堂窗口的销售额。每个食堂窗口和商铺均有多个消费结算终端,均连接到数据库服务器。客户需要先到财务处预存款才可消费。

1.2 题目分析

通过对上述题目要求的分析,总结出一个完整的校园卡消费系统需要具备:存现、转账、退款、商铺消费、窗口消费、挂失、学生信息查询、学生所有订单查询、终端消费统计等功能。

在对现实生活中校园卡消费终端的研究发现,每个终端都内置一个终端编号,每张校园卡也内置一个校园卡卡号(不是学号),比如在消费、存现的过程中,们只需要输入金额,在卡片接触终端机器时,系统会自动识别两端的编号。但在我们模拟过程中,做不到自动识别,所以需要手动的输入终端编号和校园卡卡号,然后通过卡号去查询所属学号,产生一个与学号相关的订单记录并插入到总数据库中。这样即便是更换新的校园卡时,仍然可以查询到消费记录。

但挂失就不一样了,挂失是在我们不知道卡号的情况下,需要用学号到办理中心进行卡号变更,所以输入的是学号。

2 数据库设计与实现

2.1 概念结构设计

表结构:

校园卡信息表card:

Oracle校园卡消费系统(文档+代码)_第1张图片

终端信息表terminal:

商品信息表goods:

消费记录表consume:

Oracle校园卡消费系统(文档+代码)_第2张图片

变更记录表change:

Oracle校园卡消费系统(文档+代码)_第3张图片

E-R图:

Oracle校园卡消费系统(文档+代码)_第4张图片

2.2 物理结构设计

数据库的物理设计就是根据所选用的DBMS和处理需求,进行物理存储安排,建立索引,形成数据库的内模式, 为逻辑数据模型选取一个最适合应用要求的物理结构的过程, 在这个阶段中要完成两大任务:

1)确定数据库的物理结构,在关系数据库中主要是存取方法和存储结构;

2)对物理结构进行评价,评价的重点是时间和空间效率。

为数据库中各基本表建立的索引如下:

由于基本表 card的属性user_id经常在查询条件和连接操作的连接条件中出现,考虑在这个属性上建立索引。

3 数据库实施

3.1 建立数据表、索引、序列,视图

建立5个数据表,索引为校园卡信息表中的学号属性,并分别在校园卡卡号,消费订单编号,业务办理编号上建立序列。当办理挂失业务和产生订单时,自动生成新的唯一编号。视图为财务部统计的各终端消费汇总情况,按消费金额排名。

3.2 插入初始数据

录入终端信息,校园卡信息,以及商品信息,订单信息由存储过程自动生成。

3.3 设计pl存储过程

1.商铺消费 EXECUTE sp_sql(卡号,终端编号,商品编号,商品数量);

输入校园卡编号,终端编号,商品编号,商品数量,订单号由序列自动创建、时间为当前系统时间。首先判断是否挂失,如果挂失则输出“已冻结”,如图

否则根据商品编号查找商品表goods获取商品价格,乘以数量计算订单金额,查询用户余额,如果余额不足则输出

满足即可创建订单,查寻校园卡信息表获取用户学号,插入一条新的消费记录,更改校园卡余额,获取用户姓名。根据终端编号查询终端名,最后由程序输出本次的记录,类似于小票

整个过程将4个表联系在了一起,需要注意的是创建的订单里面是学号,不是卡号便于后期查询个人消费记录。

2. 食堂消费 EXECUTE st_sql(卡号,终端编号,金额);

同上,只是没有商品数量字段,产生的订单格式一样。

3. 存现程序 EXECUTE cx_sql(卡号,金额);

输入卡号、存现金额。首先查询校园卡信息表判断是否挂失,挂失则输出校园卡已冻结,否则更改余额,并产生业务办理记录,如(交易单号、根据卡号查询的学号、默认的业务类型“存现”、存现金额、自动生成的交易时间),交易单号由序列生成。然后输出业务办理的小票

4. 退款程序 EXECUTE tk_sql(卡号);

输入卡号、首先判断是否挂失,如果未挂失则将校园卡余额更新为0,产生并插入一条业务办理记录,如(交易单号、根据卡号查询的学号、默认的业务类型“退款”、退款金额、自动生成的交易时间)。最后输出业务业务办理的小票

5.转账程序 EXECUTE zz_sql(卡号1,卡号2,金额);

输入卡号1,卡号2,转账金额。首先判断两个卡号是否挂失,然后判断转出账户金额是否充足,若条件都满足则扣减卡号1账户余额,增添卡号2账户余额,并产生业务办理记录(交易单号、根据卡号1查询的学号、默认的业务类型“转账”、转账金额、自动生成的交易时间)。最后打印小票

6.挂失程序 EXECUTE gs_sql(学号);

输入学号,查询到当前使用的校园卡卡号、为其添加“挂失”字段,然后创建新的校园卡表记录,将学号、名字、金额转移(原金额设为0),挂失字段为空。

7.查询某个账户信息 EXECUTE user_sql(学号);

输入学号,查询校园卡信息表,获得当前正在使用的卡号、姓名、余额,并打印输出

8.查询某个用户所有订单信息 EXECUTE user_order(学号,:data);  PRINT data;

输入学号,查询消费记录表,获取金额信息,将类型设置为“消费”,根据存储的终端编号查找终端信息表获得终端名,获得订单创建的时间戳。在根据学号查询变更记录表,获取金额信息,将类型设置为存储的类型{“存现”,“转账”,“退款”},地点字段为空,获得记录创建时间。然后将两个查询的结果表纵向连接,按时间先后排序,输出的一张表,这里用到了游标的知识,表的属性为(金额、类型(存现、转账、退款、消费)、地点(只有消费显示地点)、具体时间),结果如下

Oracle校园卡消费系统(文档+代码)_第5张图片

9.财务部查看各终端消费视图 select * from v_rank;

按消费金额降序排序,统计各个终端的消费情况,比如输出的字段(终端名、所在区域、累计消费金额)。

Oracle校园卡消费系统(文档+代码)_第6张图片

 

4 其它说明

4.1 遇到的问题

1.PL程序中序列的引用问题

最开始采用p_change_id:=change_seq.nextval这种形式引用,在oracle11版本上测试成功,但在oracle10版本上出错,最后使用了课本上规范的写法。

      SELECT change_seq.nextval

      INTO p_change_id

      FROM dual;

2.PL程序中多条件查询要使用括号

要根据学号查询校园卡信息表中正在使用的校园卡,一开始没有在and后面的条件外加括号,使得每次查询都出错,但过程却创建成功,网上找了很多资料也不知道什么原因,最后无意中尝试用括号括起来,成功了。WHERE user_id=p_user_id AND (card_lost is null);

3.如何输入一个参数,经查询返回一个表

一开始考虑到两个方案,一是实现能传入参数的视图,因为视图能输出表,但不能引入参数,没有找到这样应用的实例;二使用存储过程,可以传参但只能一行一行的输出,虽然使用for loop循环,但破坏了表的输出形式,经查询,网上都是使用包和游标,太复杂了就没有采用。后来随意尝试发现不用包只用游标也可以,用游标记录一个结果集,通过out传参。存储过程内定义为data out sys_refcursor;过程外定义变量为VARIABLE data refcursor;打印输出print data;
有关此问题看:https://blog.csdn.net/qq_42748385/article/details/103653710

4.2 代码


drop table card;
drop table terminal;
drop table goods;
drop table consume;
drop table change;
DROP SEQUENCE card_seq;
DROP SEQUENCE consume_seq;
DROP SEQUENCE change_seq;
drop procedure gs_sql;
drop procedure cx_sql;
drop procedure tk_sql;
drop procedure zz_sql;
drop procedure st_sql;
drop procedure sp_sql;
drop procedure user_sql;
drop procedure user_order;
drop view v_rank;

--建表
create table card(
card_id varchar2(10) primary key,
user_id varchar2(10) not null,
user_name varchar2(10) not null,
card_account float not null,
card_lost varchar2(10)check(card_lost='挂失') 
);

create table terminal(
terminal_id varchar2(10) primary key,
terminal_name varchar2(15) not null,
terminal_area varchar2(10)check(terminal_area='西区'or terminal_area='南区') not null
);

create table goods(
goods_id varchar2(10) primary key,
goods_name varchar2(10) not null,
goods_money float not null
);

create table consume(
consume_id varchar2(10) primary key,
terminal_id varchar2(10) not null,
user_id varchar2(10) not null,
consume_money float not null,
consume_time date not null
);

create table change(
change_id varchar2(10) primary key,
user_id varchar2(10) not null,
change_type varchar2(10)check(change_type='存现'or change_type='退款'or change_type='转账') not null,
change_money float not null,
change_time date not null
);

--索引
CREATE INDEX i_user_id ON card(user_id);

--序列
CREATE SEQUENCE card_seq
INCREMENT BY 1
START WITH 10000
CACHE 500
NOCYCLE;

CREATE SEQUENCE consume_seq
INCREMENT BY 1
START WITH 20000000
CACHE 500
NOCYCLE;

CREATE SEQUENCE change_seq
INCREMENT BY 1
START WITH 30000000
CACHE 500
NOCYCLE;

--插入数据
INSERT INTO card VALUES(card_seq.nextval,'1704011011','张三',100,null);
INSERT INTO card VALUES(card_seq.nextval,'1704011012','李四',1000,null);
INSERT INTO card VALUES(card_seq.nextval,'1704011021','王五',0,'挂失');
INSERT INTO card VALUES(card_seq.nextval,'1704011021','王五',100,null);

INSERT INTO goods VALUES('1','矿泉水',2);
INSERT INTO goods VALUES('2','面包',6);
INSERT INTO goods VALUES('3','饼干',4);
INSERT INTO goods VALUES('4','方便面',5);
INSERT INTO goods VALUES('5','卫生纸',3);
INSERT INTO goods VALUES('6','烤肠',1);
INSERT INTO goods VALUES('7','水壶',55);

INSERT INTO terminal VALUES('100','1食堂商店','西区');
INSERT INTO terminal VALUES('101','1食堂1-1班组','西区');
INSERT INTO terminal VALUES('102','1食堂1-2班组','西区');
INSERT INTO terminal VALUES('103','2食堂商店','西区');
INSERT INTO terminal VALUES('104','2食堂2-1班组','南区');

--存现pl
SET serveroutput ON
SET verify OFF
CREATE OR REPLACE PROCEDURE cx_sql
  (p_card_id IN card.card_id%TYPE,
    p_money IN card.card_account%TYPE)
IS
    p_user_id card.user_id%TYPE;
    p_user_name card.user_name%TYPE;
    p_card_lost card.card_lost%TYPE;
    p_change_id change.change_id%TYPE;
  BEGIN
  SELECT user_id,user_name,card_lost
  INTO p_user_id,p_user_name,p_card_lost
  FROM card
  WHERE card_id=p_card_id;
  IF p_card_lost='挂失' THEN
     DBMS_OUTPUT.PUT_LINE('存现失败,校园卡已冻结!');
  ELSE
    BEGIN
      UPDATE card SET card_account=card_account+p_money
      WHERE card_id=p_card_id;
      SELECT change_seq.nextval
      INTO p_change_id
      FROM dual;
      INSERT INTO change VALUES(p_change_id,p_user_id,'存现',p_money,SYSDATE);
      DBMS_OUTPUT.PUT_LINE('账户:'||p_user_id||p_user_name||' 存现成功,金额'||p_money||'元,交易编号:'||p_change_id);
    END;
  END IF;
END;
/

--退款pl
CREATE OR REPLACE PROCEDURE tk_sql
  (p_card_id IN card.card_id%TYPE)
IS
    p_user_id card.user_id%TYPE;
    p_user_name card.user_name%TYPE;
    p_card_account card.card_account%TYPE;
    p_card_lost card.card_lost%TYPE;
    p_change_id change.change_id%TYPE;
  BEGIN
  SELECT user_id,user_name,card_account,card_lost
  INTO p_user_id,p_user_name,p_card_account,p_card_lost
  FROM card
  WHERE card_id=p_card_id;
  IF p_card_lost='挂失' THEN
     DBMS_OUTPUT.PUT_LINE('退款失败,校园卡已冻结!');
  ELSE
    BEGIN
      UPDATE card SET card_account=0
      WHERE card_id=p_card_id;
      SELECT change_seq.nextval
      INTO p_change_id
      FROM dual;
      INSERT INTO change VALUES(p_change_id,p_user_id,'退款',p_card_account,SYSDATE);
      DBMS_OUTPUT.PUT_LINE('账户:'||p_user_id||p_user_name||' 退款成功,金额'||p_card_account||'元,交易编号:'||p_change_id);
    END;
  END IF;
END;
/

--转账pl
CREATE OR REPLACE PROCEDURE zz_sql
  ( p_card_id1 IN card.card_id%TYPE,
    p_card_id2 IN card.card_id%TYPE,
    p_money IN card.card_account%TYPE)
IS
    p_user_id1 card.user_id%TYPE;
    p_user_name1 card.user_name%TYPE;
    p_card_lost1 card.card_lost%TYPE;
    p_user_id2 card.user_id%TYPE;
    p_user_name2 card.user_name%TYPE;
    p_card_lost2 card.card_lost%TYPE;
    p_change_id change.change_id%TYPE;
    p_card_account card.card_account%TYPE;
  BEGIN
  SELECT user_id,user_name,card_account,card_lost
  INTO p_user_id1,p_user_name1,p_card_account,p_card_lost1
  FROM card
  WHERE card_id=p_card_id1;
  SELECT user_id,user_name,card_lost
  INTO p_user_id2,p_user_name2,p_card_lost2
  FROM card
  WHERE card_id=p_card_id2;
  IF p_card_lost1='挂失' THEN
    DBMS_OUTPUT.PUT_LINE('转账失败,'||p_card_id1||'已冻结!');
  ELSIF p_card_lost2='挂失' THEN
    DBMS_OUTPUT.PUT_LINE('转账失败,'||p_card_id2||'已冻结!');
  ELSE
    BEGIN
    IF p_card_account

 

你可能感兴趣的:(项目之路,报告,数据库)