今天是一个美好的周末,同时也是一个愉快的加班日。
享受着福报的我可是第一个到公司的哦,对于这辈子乃至下辈子都无法成为周衙内的我对于自我的定位可是门清的很,自然工作要加倍努力加油啦!
什么?我不是第一个到公司的?
同事小范工位上那屏幕闪烁的电脑和一堆零乱摆放的物品暗示着我并非第一个到达公司!
我突然感到有些失落,这完全就是打击我的积极性嘛!
话说这位小范同学,大名范坤,我们系统组的一员。
平时工作能力还行,态度却很一般,经常喜欢上班时划水摸鱼。
记得有那么两次就被周吉和周力两位董事长太子给逮个正着,听说是躲厕所里玩王者呢!
我决定待会质问质问这小子,啥时候开始洗心革面卷成这个鸟样了?!
可是左等右等不见人影,我心想,这小子不会跟我玩消失吧,一会儿还有工作要做呢!
不对啊,这都快一个小时了,活不见人死不见尸的,等会耽误了加班工作可不行啊!
哎,会不会又摔茅坑里出不来了,淦,我决定亲自把这小子给提溜回来!
我简单整理了一下工位,左右环顾确保没人注意到这边发生的异样后,一溜烟跑到了同楼层的厕所门外。
周末的楼道里显得非常冷清,配合上那闪烁不定本来就暗淡无光快要挂掉的破照明灯,那简直就是千山鸟飞绝,万径人踪灭,拍鬼片都比影视基地都更合适!
当然了,我胆子没那么小,大白天的还能闹鬼不成?!
再说,我可是正在气头上,冲进厕所就喊道:“小范,你小子在哪儿呢?别...别躲着玩了!赶紧的...快...快...出来工作啦!我都闻...闻到味儿,呸...”
哎,奇了怪了,根本没动静!
我退了出来,眨巴眨巴眼睛再次确认是男厕所没错后又走了进去,心想这小子是不是玩入迷了,不搭理我啊这是。
可是极其诡异的一幕发生了,我挨个蹲位查看,不管是黄金至尊蹲位还是乞丐忆苦思甜蹲位,都特么没人!
我大吃一惊,不由得倒吸一口冷气,暗自里喃喃道:“哎呦我去!这大白天的闹鬼了啊,难不成这小子遁地了不成?”
我这话刚一说完,就听厕所门口传来一阵“呼呼”声!
我壮着胆子循声音再走近一听,突然鼾声如雷,我心里话,这是哪位老神仙显灵啊,差点就给跪了!
正在纳闷时这才发现这厕所还有一间较为隐蔽的杂物间。
这杂物间平时都是放一些打扫厕所的工具物品,怎么会有怪声从中传出,难道皮搋子成精了?
我定了定神,一把拉开杂物间虚掩的房门,就看见有一人正蜷缩在狭小阴暗的角落处。
我上前仔细一瞧,差点鼻子给气歪了,这特么不就是我要找的小范同学嘛!
事后我才得知,这小子昨晚就在公司加班搞了个通宵,直到现在都没回家,没想到上个厕所实在太困就阴差阳错地睡上杂物间了。
我说你小子可真行,干啥玩意就这么拼命了,还跟我玩内卷哈!
在我一再询问下,才知道这小子为了调试某个数据库系统,由于没有现成的示例数据库样本,因此只好自己徒手构建测试用的数据库。
你要说简单点的测试也就罢了,可是眼前的数据库需要测试的内容比较复杂,不光涉及到一般的查询,数据量要求还挺大,自己徒手创建费时费力非常困难,可能使用起来效果也不太理想。
我拍了拍他稚嫩的小肩膀,语重心长地告诉他,实际上是有现成示例数据库可以直接拿来用的。
我不说还没事,他这么一听突然崩溃了,泪水夺眶而出,吱吱呜呜求我一定要教他,这示例数据库怎么个整法。
我长叹一声,瞥了一眼微信的余额后安慰他说,我这人吧最见不得别人吃苦受累、可怜巴巴,放心这忙我肯定帮,不过有些小条件哈......
示例数据库 Sakila
Sakila
数据库是一个很棒的标准化数据库,它模拟了一家 DVD
出租商店(那些年龄稍长的人应该知道那是什么)所需的所有可能的表和数据。
这个示例数据库被设计为具有如下一些很乃斯的功能:
- 多对多关系
- 数据表之间存在多条路径(例如,电影-库存-租金-支付与电影-库存-商店-客户-支付)可用于练习表关联
Joins
- 数据列的一致性命名
- 主键被统一定义为
[tablename]_[id]
- 如果可能,外键的调用方式与其引用的主键一样。这允许在系统支持的情况下使用
JOIN .. USING
语法 - 关系表没有任何代理键但使用复合主键
- 每个表都有一个
last_update
审计列 - 有一个合理大小的生成数据集可用
- 主键被统一定义为
Sakila
提供了不止一种数据库系统平台的支持,常见的 MySQL
、 SQL Server
、 Oracle
等等都有。
对于手里有两种以上的数据库系统的小伙伴来说,这真的是灰常棒的工具啊(擦擦口水)!
你瞧,激动得我开始说起了普通发......
(文末有 Sakila
示例数据库打包下载)
SQL
导入文件
即使有多个不同的数据库系统平台也不用担心,Sakila
完全提供了针对不同平台的 SQL
文件。
通常每种平台会有四个这样的文件,分别如下:
sakila-schema.sql
- 生成数据表(结构)sakila-insert-data.sql
- 插入数据sakila-delete-data.sql
- 删除数据sakila-drop-objects.sql
- 删除数据表(结构)
你看,这些文件从其命名就可以看出,它们是一伙的,既体现了数据构架的顺序,又相辅相成、各司其职。
在实际使用中,我们也可以针对它们的职能分别灵活运用即可。
注意,在插入数据时,会因为SQL语句没有批量整合而导致导入速度非常缓慢,需要和小伙伴们提前打个招呼。
接下来我们简单地看看 Sakila
数据库长什么样子。
Sakila
数据表展示
这个 Sakila
数据库包含了23个表。
拿几个主要的表举例吧。
actor
- 演员
address
- 地址
category
- 影片分类
city
- 城市
country
- 国家
customer
- 观影用户
film
- 影片
film_actor
- 影片演员关联表
film_category
- 影片分类关联表
file_text
- 影片描述
inventory
- 库存
payment
- 租赁付款
rental
- 影片库存租赁
staff
- 商店员工信息
store
- 影片商店
数据表关联图 ERD
从前面的表结构我们多少能看出来,这个 Sakila
示例数据库是真心简单而又不失完整性,可以说既照顾到了易懂易用,但又不复杂繁琐。
有23张数据表也不算少了,虽然每张表的字段不算多复杂,但要在短时间内厘清各表之间的结构,我想怎么也得花上数个钟头吧!
其实大神早就帮我们准备好了一份 Sakila
示例数据库各表之间的关联图。
看看,就是下面这个样子。
被吓到了吗?
其实作为示例数据库,它总是要考虑到大多数使用数据库的场景嘛,因此多少肯定会有一些交叉关联的情况出现。
不过请放心,这款示例数据库已经精简得很多了,作为测试调试程序已经足够使用了。
好了,静下心来,慢慢学习吧!
查询测试
一旦示例数据库 Sakila
被导入到了系统中,那么我们就可以开始测试使用它了,比如做一些查询工作。
请注意啦,不同的数据库系统所支持的 SQL
语法可能差别非常大,需要认真区分。
比如,使用 MySQL/PostgreSQL
来查询出演影片较多的演员。
SELECT first_name, last_name, count(*) films
FROM actor AS a
JOIN film_actor AS fa USING (actor_id)
GROUP BY actor_id, first_name, last_name
ORDER BY films DESC
LIMIT 1;
所得出的结果:
first_name last_name films
--------------------------------
GINA DEGENERES 42
再比如,查询全店累计收入是多少。
此处需特别注意,如果你使用的是 MySQL 5.7
,那么爱木骚瑞,这个版本是不支持 OVER
函数的,可以使用 MySQL 8.0
。
我在这儿浪费了半个多小时,希望小伙伴们不要在此上当浪费时间!
SELECT payment_date, amount, sum(amount) OVER (ORDER BY payment_date)
FROM (
SELECT CAST(payment_date AS DATE) AS payment_date, SUM(amount) AS amount
FROM payment
GROUP BY CAST(payment_date AS DATE)
) p
ORDER BY payment_date;
所得出的结果:
payment_date amount sum
-------------------------------------
2005-05-24 29.92 29.92
2005-05-25 573.63 603.55
2005-05-26 754.26 1357.81
2005-05-27 685.33 2043.14
2005-05-28 804.04 2847.18
2005-05-29 648.46 3495.64
2005-05-30 628.42 4124.06
2005-05-31 700.37 4824.43
2005-06-14 57.84 4882.27
2005-06-15 1376.52 6258.79
2005-06-16 1349.76 7608.55
2005-06-17 1332.75 8941.30
...
尝试在其他平台上使用 Sakila
通常 Sakila
在 MySQL/PostgreSQL
上表现OK,但是其他数据库系统上也能用吗?
毕竟现在还是有不少地方使用的是微软的 SQL Server
,还有很多大型企业用的则是 Oracle
。
因此,我也尝试了一下在更多的系统平台上导入测试 Sakila
。
首先,我们将目光转到 SQL Server
这边。
我们先开一个大大的窗口来新建查询。
亦或者直接选择文件打开。
同样在 sql-server-sakila-db
文件夹中也有四个 SQL
文件,我们将创建框架 schema
的文件加载上来。
sql-server-sakila-db\sql-server-sakila-schema.sql
点击执行按钮跑一下刚才加载的 SQL
,从结果来看似乎一切顺利!
名为 sakila
的数据库被成功创建。
接下来如法炮制,加载插入数据集的 SQL
文件。
sql-server-sakila-db\sql-server-sakila-insert-data.sql
当点击执行按钮后,我的心彻底地凉了!
乖乖!居然报了这么多的错!
然后就是一番搏斗了,请往下看。
简言之,就是有几个表中的字段类型似乎有些问题,从而导致表与表之间的外键关联也同样出错。
比如其中, tinyint
类型只能表示 0~255
范围内的整数,可从这个字段的字面意思上看呢, manager_staff_id
好像是工作管理人员的编号,难道工作人员最多只有255个?
哦,好像租碟的小店不太会有这么多的员工哈!
要是做大做强开连锁店呢?
这里似乎有作者改动过的痕迹,有点想不通为啥要在这儿将 int
变成 tinyint
,这里还牵扯到了索引并关联了其他表,好吧,干脆注释掉这些行试试吧!
(文末有 SQL Server
修正版 Sakila
示例数据库下载)
大体修改总结如下:
创建 staff
表语句。
大概第 261
行:
staff_id INT NOT NULL IDENTITY,
修改成
staff_id TINYINT NOT NULL IDENTITY,
创建表 store
语句中。
大概第 289
行:
manager_staff_id INT NOT NULL,
修改成
manager_staff_id TINYINT NOT NULL,
创建表 payment
语句中。
大概第 313
行:
staff_id INT NOT NULL,
修改成
staff_id TINYINT NOT NULL,
创建表 rental
语句中。
大概第 340
行:
staff_id INT NOT NULL,
修改成
staff_id TINYINT NOT NULL,
好了,应该就是这么多了吧,再导入试试看!
OK!这次没毛病了!
请小伙伴们注意,在反复尝试导入数据失败时,你可以使用 Sakila
自身提供的删除 SQL
语句文件,也可以自行动手清空删除数据。
前者方法与前面导入数据一样。
删除清空数据。
sql-server-sakila-db\sql-server-sakila-delete-data.sql
删除 Sakila
数据库。
sql-server-sakila-db\sql-server-sakila-drop-objects.sql
好了,既然有数据了,那我们就来测试一下 SQL
语句查询输出。
再试试复杂一些的官网示例语句,查询出演电影次数最多的演员。
官网示例语句是 PgSQL
语法的,我们稍稍修改一下看看。
SELECT TOP 1 first_name, last_name, count(*) films
FROM actor AS a
JOIN film_actor AS fa
ON fa.actor_id=a.actor_id
GROUP BY fa.actor_id, first_name, last_name
ORDER BY films DESC
再来查询一下,全店累计收入。
这个语句不用怎么修改直接就能用,毕竟要钱滴,比 MySQL 5.7
强多了。
SELECT payment_date, amount, sum(amount) OVER (ORDER BY payment_date) as sum
FROM (
SELECT CAST(payment_date AS DATE) AS payment_date, SUM(amount) AS amount
FROM payment
GROUP BY CAST(payment_date AS DATE)
) p
ORDER BY payment_date;
最后再来试试 Oracle
。
如何导入就不多说了,这里看看测试结果。
Oracle
并不支持 limit
语法,因此查询语句需要调整一下。
SELECT *
FROM (
SELECT first_name, last_name, count(*) films
FROM [模式].actor a
JOIN [模式].film_actor USING (actor_id)
GROUP BY actor_id, first_name, last_name
ORDER BY films DESC
)
WHERE rownum = 1
再来查询一下,全店累计收入。
SQL
语句还是要改一改啊,我太难了!
这里有个坑,Oracle
好像 Date
类型总是表现为长日期,因此不得不改用类型转换。
SELECT payment_date, amount, SUM(amount) OVER(ORDER BY payment_date) AS SUM
FROM (
SELECT to_date(to_char(payment_date, 'yyyy-mm-dd'),'yyyy-mm-dd') AS payment_date, SUM(amount) AS amount
FROM [模式].PAYMENT a
GROUP BY to_date(to_char(payment_date, 'yyyy-mm-dd'),'yyyy-mm-dd')
) p
ORDER BY payment_date;
写在最后
好了,前面我花了好几天的时间,将一些看得见和看不见的坑都踩了一踩,希望小伙伴们看到这些坑可以顺利地跳过去。
另外,大家可以直接去 Github
下载 Sakila
的源代码,不方便下载的也可以到我这儿搬走。
sakila-main.zip (5.25M)
下载链接:https://pan.baidu.com/s/1v2AiZ-sx-ZQPaN_6l-Rt7Q
提取码:
★扫码关注公众号, 发送【000968】获取阅读密码
sql-server-sakila-db.7z (1.41M)
下载链接:https://pan.baidu.com/s/1S25MiOMJlPdIZIWemPlNew
提取码:
★扫码关注公众号, 发送【000968】获取阅读密码
OK,截止到目前为止,我们试过了好几个数据库平台了,基本上都能很好地运用 Sakila
这个示例数据库。
除此之外,还有好几个系统我暂时没时间测试了,比如 db2
、 sqlite
等等,我猜多多少少也有小伙伴要用到的,还是有测试价值的,所以就当家庭作业,各位回去慢慢研究吧!
最后如果你觉得多多少少有所收获,回来再看的机会也不多,大家都这么忙是吧,哈哈,那么请顺手点一点,让这篇文章的样子更好看一点儿,谢谢!
扫码关注@网管小贾,个人微信:sysadmcc
网管小贾 / sysadm.cc