数据库设计|游戏-玩家-活动数据库|期末课程设计

前言

那么这里博主先安利一些干货满满的专栏了!

首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助。

高质量博客汇总https://blog.csdn.net/yu_cblog/category_12379430.html?spm=1001.2014.3001.5482


设计内容 

请为某游戏公司设计一个简单数据库。需求如下:玩家可以登录该公司运营 的多款游戏,登录游戏可以玩该游戏,也可以为该游戏充值。游戏会经常性推出 一些活动,玩家可以参与某些活动。

说明:

  1. 游戏的类型包括:免费和非免费。玩非免费游戏需要付费
  2. 一个玩家可以不参加,或者最多参加 10 个活动
  3. 一个活动可以有任意多个玩家参加

概念设计(ER图)

题目要求:

画出完整的E-R模型图。

标出映射基数(One to one,One to many,Many to many)、参与的类型(部分和全部),以及主码。 结果如Fig1所示。其中下划线表示表的主码。

Fig.1
Fig.1 数据库ER图,以及映射基数、参与类型的标注

关系模式

题目要求:把E-R图转换为关系模式,并标出主码。

如图所示,关系模式如Fig2所示。

Fig.2 数据库的关系模式

 所有表的主码用下划线进行表示。

SQL代码

建表SQL语句和关系模式的相关约束

建立游戏实体表

CREATE TABLE Games (
  GameID Counter PRIMARY KEY, 
  GameName varchar(255) NOT NULL, 
  Cost money default 0, 
  GameType varchar(10) default 免费 NOT NULL
);

相关约束

GameID:游戏ID(计数器)

GameName:游戏名称(最大长度为255的字符串)

Cost:游戏费用(默认为0的货币类型)

GameType:游戏类型(默认为“免费”,长度为10的字符串,在非空约束下,并且约束为其值只能是“付费”或者“免费”两者之一)

设置游戏表的名为GamesRule的约束,约束游戏类型只能是'免费'或'付费'

ALTER TABLE Games ADD CONSTRAINT GamesRule CHECK (GameType IN ('免费', '付费'));

建立活动实体表

CREATE TABLE Activities (
  ActivityID Counter PRIMARY KEY, 
  ActivityName varchar(255) NOT NULL
);

相关约束

ActivityID:活动ID(计数器)

ActivityName:活动名称(最大长度为255的字符串,在非空约束下)

建立玩家实体表

CREATE TABLE Players (
  PlayerID Counter PRIMARY KEY, 
  PlayerName varchar(255) NOT NULL, 
  PlayerPass varchar(255) NOT NULL
);

相关约束

PlayerID:玩家ID(计数器)

PlayerName:玩家名称(最大长度为255的字符串,在非空约束下)

PlayerPass:玩家密码(最大长度为255的字符串,在非空约束下)

建立玩家游戏关系表(登陆表)

CREATE TABLE Login (
  PlayerID INT,
  GameID INT,
  ParticipateActivity BIT DEFAULT 0,
  Balance MONEY NOT NULL DEFAULT 0,
  LoginTime DATETIME DEFAULT GETDATE(),
  FOREIGN KEY (PlayerID) REFERENCES Players(PlayerID),
  FOREIGN KEY (GameID) REFERENCES Games(GameID)
);

相关约束

PlayerID:玩家ID(整数)

GameID:游戏ID(整数)

ParticipateActivity:是否参与活动(默认为0的位数据类型)

Balance money:余额(非空约束下,默认为0的货币类型)

LoginTime:上一次登陆时间(DATETIME类型)

外键约束:PlayerID 外键参考 Players(PlayerID),GameID 外键参考 Games(GameID)

建立游戏活动关系表

CREATE TABLE GameActivities (
  GameID int, 
  ActivityID int, 
  FOREIGN KEY (GameID) REFERENCES Games(GameID),
  FOREIGN KEY (ActivityID) REFERENCES Activities(ActivityID)
);

相关约束

GameID:游戏ID(整数)

ActivityID:活动ID(整数)

外键约束:GameID 外键参考 Games(GameID),ActivityID 外键参考 Activities(ActivityID)

建立玩家活动关系表

CREATE TABLE PlayerActivities (
  PlayerID int,
  ActivityID int, 
  FOREIGN KEY (PlayerID) REFERENCES Players(PlayerID), 
  FOREIGN KEY (ActivityID) REFERENCES Activities(ActivityID)
);

相关约束

PlayerID:玩家ID(整数)

ActivityID:活动ID(整数)

外键约束:PlayerID 外键参考 Players(PlayerID),ActivityID 外键参考 Activities(ActivityID)

创建触发器

创建触发器检查玩家参加的活动数是否已达上限10

CREATE TRIGGER LimitPlayerActivities
BEFORE INSERT ON Login
FOR EACH ROW
BEGIN
    DECLARE total_activities INT;
    -- 计算
    SELECT COUNT(*) INTO total_activities
    FROM Login
    WHERE PlayerID = NEW.PlayerID;
    
    IF total_activities >= 10 THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'A player can participate in a maximum of 10 activities.';
    END IF;
END;

查询

查找所有的参与了游戏A推出的所有活动的玩家的sql语句

SELECT DISTINCT Players.PlayerID, Players.PlayerName
FROM Players
INNER JOIN Login ON Players.PlayerID = Login.PlayerID
INNER JOIN GameActivities ON Login.GameID = GameActivities.GameID
INNER JOIN Activities ON GameActivities.ActivityID = Activities.ActivityID
INNER JOIN Games ON GameActivities.GameID = Games.GameID
WHERE Games.GameName = 'A';

找出推出活动次数超过3次的游戏的sql语句

SELECT G.GameID, G.GameName, COUNT(GA.ActivityID) AS ActivityCount
FROM Games G
JOIN GameActivities GA ON G.GameID = GA.GameID
GROUP BY G.GameID, G.GameName
HAVING COUNT(GA.ActivityID) > 3; 

查找所有为游戏A充值高于某位玩家的玩家ID的关系代数

 这个关系代数的公式描述了一系列操作,每一步的含义和目的如下:

  1. Login ⨝ Players 这一步使用了⨝运算符,它表示连接操作,将"Login"和"Players"关系进行连接。连接操作基于两个关系之间的公共属性,将满足连接条件的元组组合在一起。这一步的目的是将"Login"和"Players"关系中的数据进行连接,以便后续操作使用。

  2. ρ PlayerID/PlayerID (Login ⨝ Players) 这一步使用了ρ运算符,它的作用是对关系进行重命名。在这个公式中,我们将"Login ⨝ Players"的结果重命名为"PlayerID",也就是将结果中的PlayerID字段重命名为PlayerID。这一步的目的是为了更好地表达下一步的操作。

  3. σ GameName='A' ⨝ Balance > Amount 这一步使用了σ运算符,它的作用是对关系进行选择操作,即根据给定的条件筛选出符合条件的元组。在这个公式中,我们选择了GameName为'A'且Balance大于Amount的元组。这一步的目的是根据特定条件过滤出符合要求的数据。

  4. π PlayerID 这一步使用了π运算符,它的作用是对关系进行投影操作,即只保留指定的属性列。在这个公式中,我们只保留了PlayerID属性列,而其他属性列被排除在外。这一步的目的是从上一步筛选出的结果中仅保留PlayerID属性,以便得到最终的结果。

综上所述,该关系代数的公式的含义是:从"Login"和"Players"关系中连接(⨝)所有匹配的元组,然后根据条件选择(σ)GameName为'A'且Balance大于Amount的元组,并最终只保留(π)PlayerID属性列。这样操作的目的是查找所有充值高于某位玩家的玩家ID。

设计若干个实用的SQL过程和函数

统计给定游戏,所有登录(玩付费游戏)人数(函数)

CREATE PROCEDURE GetLoginCountByGameName(IN gameName VARCHAR(255), OUT loginCount INT)
BEGIN
    SELECT COUNT(DISTINCT PlayerID) INTO loginCount
    FROM Login
    INNER JOIN Games ON Login.GameID = Games.GameID
    WHERE Games.GameName = gameName;
END;
-- 调用
CALL GetLoginCountByGameName('A', @loginCount);
SELECT @loginCount;

统计给定游戏,当天所有玩家付费的总额(过程)

首先我们需要创建存储过程,存储过程的输入参数是1个代表着游戏名称,输出结果是一个代表着总额,并且会利用到SUM聚合函数来做总额计算,我们需要将玩家-游戏表和游戏表做内连接,内连接条件是游戏ID相等,并加上where子句,这样我们就可以得到所有玩了输入参数指定的游戏的玩家记录和其对应的游戏耗费,此时将耗费求和就是最终的总额结果了,我们select输出这个总额结果即可。最后我们测试调用存储过程CalculateTotalPaymentsByGameName,可以发现得到了正确的值。SQL代码如下。

CREATE PROCEDURE CalculateTotalPaymentsByGameName(IN gameName VARCHAR(255), OUT totalPayments DECIMAL(10, 2))
BEGIN
    SELECT SUM(Games.Cost) INTO totalPayments
    FROM Games
    INNER JOIN Login ON Login.GameID = Games.GameID
    WHERE Games.GameName = gameName;
END;
CALL CalculateTotalPaymentsByGameName('A', @totalPayments);
SELECT @totalPayments;

设计一个实用的SQL触发器

删除一个玩家时,连同该玩家的相关信息(所有游戏和活动)一同删除

DELIMITER // 
CREATE TRIGGER trg_DeletePlayer
BEFORE DELETE ON Players
FOR EACH ROW
BEGIN
  -- 删除与该玩家相关的Login记录
  DELETE FROM Login WHERE PlayerID = OLD.PlayerID;
  -- 删除与该玩家相关的PlayerActivities记录
  DELETE FROM PlayerActivities WHERE PlayerID = OLD.PlayerID;
END //
DELIMITER ;
posted @ 2023-08-07 23:20  背包Yu  阅读(28)  评论(0编辑  收藏  举报  来源