问题来源

我们有一个羽毛球小组,不定期组织打球,会产生场地费和球费,每次收钱特别琐碎,所以组长(现任组长其实就是我)每次开学就让大家先交100块,然后记账再从交的费用里面扣。前任组长专业是CS的(其实现任组长也是,也就是我),他设了一个网站(其实是学校的一个服务器),但是这个网站是基于XML的,每次更新都要打开XML文件一项一项地更新,而且还要自己计算每个人的费用。在前任组长把工作转交给我之后我第一件事就是对网站改版,因为作为程序员,简单重复性工作真的是不能忍的事!

但其实我没学过网页编程,不会Javascript和PHP,但是我懂数据库呀!我会C++啊!秉着天下语言源出一宗的思想,我想只要会一种语言,其它都应该是很容易学的吧!结果根本不是……没有网络基础这些语言真的好难学……难虽然难,但还是设计出了一个简易的网站让我可以在网页上更新费用,让大家可以在网页上查询羽球小组的财务状况。服务器用的是实验室的NAS.

需求

羽球小组大概有二十多个人,每年都有新进成员,也有人退出(毕业了),每学期大概缴费一次。每次活动产生的费用包括球费和场地费,这些费用由所有参加活动的成员平摊。

因此这个数据库需要记录:

  • 小组成员信息
  • 成员每次缴费的信息
  • 每次活动产生的费用
  • 每次活动参加的人员

小组成员可以:

  • 查询每次活动的费用记录
  • 查询每次活动的出席人员
  • 查询自己会费的余额
  • 查询自己的缴费记录

我要:

  • 输入每次活动的日期
  • 输入每次活动参加的人员
  • 输入每次活动的费用

设计

根据上述需求,该业务的ER图如下。为了充分满足数据库设计的范式要求,设计了三个实体,两个关系,所以一共要有五张表。下图的设计至少满足第二范式(2NF),是否满足第三范式呢?仔细看了一下,好像满足。若要满足更高的范式,就需要拆分更多的表,SQL语句也会更复杂。注意到下图中没有一张表会存储『某个组员在一次球事中花费了多少钱』这样的信息,也没有『某个组员的会费余额是多少』这样的信息。因此查询这样的信息时SQL语句会稍微复杂一点,但这样的设计会减少表的信息冗余。

数据库搭建

数据库使用的是MySQL。Mac上推荐MyAdmin套件,Ubuntu上推荐phpMyAdmin套件。各种设置都设定好了,可以让人直接关注业务。根据以上ER图,设计了五张表,名称分别为:

  • memeber_t
  • memact_t(对应Attend)
  • activity_t
  • fee_t
  • memfee_t (对应Pay_Fee)

整个网站搭设在实验室的NAS上。NAS真是个好东西,写好后直接往上一丢即可。

编码工作与SQL语句编写

数据库的设计不难,难的是网页查询展示的工作以及SQL语句的编写。这个网站后台用的是PHP语言。但我用PHP的时候被实验室的人鄙视了……觉得PHP太古老,应该用Ruby。

在编写网站时用到了AJAX技术,但其实AJAX不是我的研究重点,所以这篇文章先略过吧……

下面给出5张表的截图,针对实际的查询需求编写一些SQL语句。

  • member_t

  • activity_t

  • memact_t (对应Attend)

  • fee_t

  • memfee_t (对应Pay_Fee)

发现fper_income这个字段表示组员交的会费。发现这个字段中有负数?负数的意思就是退钱给组员,使得总结余为0. 通常是毕业的组员这个字段会出现负数。

所有的查询都是根据姓名来查询,姓名对应member_t表中的name字段。下图是这个网站的查询页面(还有个管理页面)截图,很丑,实验室的人看到只有一片揶揄……不过初始目的和主要功能都满足了,作为一个功能性的网站,就不要太注重外观了。

  • 根据姓名(name)查询该组员参加的所有打球场次的信息,包括打球日期,场地费,球费,该场次的人数,该组员应付的费用,打球举办的场所(INNER JOIN)

上述查询横跨三张表的信息,因此需要连接三张表。该组员应付的费用意思是场地费加上球费再除以参与打球的人数。但是有时候有些会员会带朋友来打球,而那位朋友不在系统里,所以这个会员此时就要帮他朋友支付费用,因此在memact_t表中会多出一个adj_balance的字段。

实际操作中在后台并不是根据姓名来查询,而是根据member_t.mid字段(主键)来查询。假设已经知道user_id,SQL语句如下:

SELECT A.adate, A.asite_fee, A.aball_fee, A.aperson_num, A.aplace, B.adj_balance, (A.asite_fee+A.aball_fee)/A.aperson_num + B.adj_balance
FROMactivity_t AS A, memact_t AS B
WHEREmemact_t.mid = user_id
ANDmemact_t.aid = activity_t.aid

上述SQL语句实际是INNER JOIN操作,也可以使用INNER JOIN关键字将上述语句改写成下面的形式:

SELECT A.adate, A.asite_fee, A.aball_fee, A.aperson_num, A.aplace, memact_t.adj_balance
FROM activity_t AS A
INNER JOIN memact_t ON memact_t.aid = activity_t.aid
AND memact_t.mid = 2
  • 根据姓名(name)查询该组员的缴费记录,包括缴费日期,每次缴费的费用(INNER JOIN)

上述操作仍然是INNER JOIN操作,SQL语句如下:

SELECT memfee_t.fper_income, fee_t.date
FROM memfee_t, fee_t
WHERE memfee_t.mid = user_id AND memfee_t.fid = fee_t.fid

这段SQL也可以改写成用关键字INNER JOIN的形式。

  • 根据姓名(name)查询该组员的费用结余以,总缴费与总支出

一个会员的费用结余 = 总缴费 - 总支出。总缴费和总支出都没有直接记录在表中,横跨四张表,要将这三个结果同时写到一个SQL语句有点复杂……所以实际的编码中是分开写成两个SQL语句,一个是总缴费,一个是总支出。

总缴费:

SELECT SUM(memfee_t.fper_income) FROM memfee_t WHERE mid = user_id

总支出:

SELECT SUM((A.asite_fee + A.aball_fee) / A.aperson_num + B.adj_balance)
FROMactivity_t AS A, memact_t AS B
WHEREB.mid = user_id AND A.aid = B.aid
  • 根据日期查询这天参加打球的组员名单(IN语句)

上述查询需要用到IN语句。IN语句可以在WHERE字句内指定多个值,很好用。下面是这个查询的SQL语句,用了两个IN语句,第一个IN字句中嵌套了第二个IN。原因是因为同一个日期有可能会返回多个activity_aid(就是一天打了不止一场球)。

SELECT member_t.chname
FROM member_t
WHERE member_t.mid IN (SELECT memact_t.mid FROM memact_t WHERE memact_t.aid IN (SELECT activity_t.aid FROM activity_t WHERE activity_t.adate = '2015-03-14'))

写本文的动机

这个网站在我入学的时候就写好了,现在已经差不多过去两年了。因为需要将工作转交给下一任组长,因此需要将整个网站一起移交。所以需要有一份文档记录。同时,因为面试总是会被问到SQL语句的问题。当初写这个网站时查询了很多SQL语句的写法,但作为一个比较『激进』的实验室,大家都不太喜欢传统的关系型数据库,所以很久不用会忘记,每次面试我的回答都是『需要用的时候我会查』。感觉这个答案不太好,所以写这篇文章也是为了复习一下SQL的语法……

另外一直想在改进一下这个网站。目前主要功能还是查询,其实是为了公示每次打球的费用,没有线上自动交费的功能,如果线上自动线上交费我也就不用那么辛苦每个人收钱了……

基於MySQL+PHP的羽毛球費用查询网站设计相关推荐

  1. 基于java旅游网站设计计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署

    基于java旅游网站设计计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署 基于java旅游网站设计计算机毕业设计源码+系统+lw文档+mysql数据库+调试部署 本源码技术栈: 项目架构 ...

  2. quartus ii matlab,基於Quartus II和MATLAB的FIR濾波器設計與仿真(二)

    接上文  基於Quartus II和MATLAB的FIR濾波器設計與仿真(一): 3  QuartusII 調用 IP 核生成 FIR 濾波器模塊 在 Quartus II 中, Altera 提供了 ...

  3. 基於IIS的WCF的分布式多層架構開發實現

    曾用.NET Remoting,基於IIS,為公司實現過分布式多層架構,客戶端采用Web Browser瀏覽,當時,公司領導告訴我可能會有多臺中間服務器用於系統,又不想每臺電腦的去安裝程序,所以,我最 ...

  4. python笑傲江湖统计字数_基於Python的tf-idf算法实现:以《笑傲江湖》为例

    连结Jasonnor/tf-idf-python​github.com 简介 tf-idf(term frequency-inverse document frequency)是一种用於信息检索与文字 ...

  5. php complex,PHP復雜的基於角色的訪問控制列表

    I have already made the database and the php code needed to implement this customized ACL system. No ...

  6. linux下复制catalog信息指令,基於Linux下catalog方式的 Oracle 備份策略(RMAN)

    --********************************** --基於Linux下 Oracle備份策略(RMAN) --********************************* ...

  7. python 读取qq群消息_基於Python自動發送QQ群消息

    1.准備工作 此次測試基於python3,需要安裝qqbot.bs4.requests庫. qqbot項目地址:https://github.com/pandolia/qqbot.git pip qq ...

  8. mt7601的linux驱动下载,mt7601u,基於 Linux mac80211 MT7601U USB bgn無線dongle驅動程序,下載mt7601u的源碼_GitHub_開發99...

    這是一款用於 MT7601U USB dongle的Linux驅動程序. 它是基於供應商gpl驅動程序從頭開始編寫的. 供應商驅動程序不同,這個驅動程序使用現代的Linux WiFi基礎設施,並且應該 ...

  9. netty框架android,隻需五步,即可基於Netty框架實現Android內網推送功能。

    隻需五步,即可基於Netty框架實現Android內網推送功能. 一.先引入依賴,客戶端和服務端用的都是同一個依賴netty-all. Android Studio中Gradle配置: compile ...

最新文章

  1. 奇葩错误:cv.imread()读取失败
  2. MySql The service could not be started
  3. 持币过节也能让钱生钱
  4. aidl demo调用原理
  5. mysql单表备份语句 +多表
  6. java之Stack详细介绍
  7. 腾讯再出新招!社交新产品“有记”已上线?
  8. 读程序员网游专题云风的文章有感
  9. SQL Server高级查询之子查询(在DML语句中使用子查询)
  10. (转) 穿越NAT总结
  11. MFC 的几个常用函数,用来计算文件大小,下载速度,转换时间的
  12. 纯虚函数的类为什么不能被实例化
  13. 转换PDF技巧1之PDF虚拟打印机操作详解
  14. SIM868模块+Arduino将位置信息上传到服务器
  15. 神秘的程序员头像包(附口罩版)第一发
  16. Linux/Windows快速镜像安装包下载
  17. 计算机快捷方式后缀名,win10系统去掉“快捷方式”四个字后缀名的操作方案
  18. Fedora 17下NVIDIA双显卡闭源驱动的安装
  19. 正则表达式中的特殊字符一览
  20. hdu5172 GTY‘s gay friends(hash判断排列)

热门文章

  1. laravel-admin form中的数据,在提交后,保存前,获取并进行编辑
  2. 2015第25周三iframe小结
  3. shell 脚本编程的10 个最佳实践
  4. redmine只是管理插件redmine_knowledgebase升级到0.4.0
  5. Dynamics AX 2012–HR-离职
  6. 利用优先级队列实现堆栈
  7. CentOS上使用Docker安装Redis-Cluster (redis6.x)
  8. 使用模块化工具Rollup打包自己开发的JS库
  9. Windows上面挂载NFS共享
  10. SpringBoot之项目运行常见报错