网易2018校园招聘数据分析工程师笔试卷 —— SQL整理

题目

现有一个会议室预定系统,包含如下表实体:

  • 用户表(用户id,用户名,部门,职位);
  • 会议室表(会议室id,办公楼编号,楼层,会议室门牌,会议室类型id);
  • 会议室类型(类型id,容纳人数,是否有投影仪,是否有电话,是否有视频电话);
  • 会议订阅表(用户id,会议室id,订阅开始时间,订阅结束时间)
  1. 请根据以上表结构写出建表的sql语句,注意选择合适的字段类型和主键。
  2. 有需求查出2017-09-11 10:00:00 至 2017-09-11 12:00:00没有被人预定过的会议室id列表,要求容纳人数在10人以上,有投影仪和视频电话。请问这个sql语句如何编写,如何添加索引加速这个查下。
  3. 假设订阅一个会议室包括两个步骤:1.查询出可以预定的会议室列表。2.插入会议订阅表(包含订阅的时间和用户id,会议室id)表示预定。请问如果两个用户同时预定,如何利用数据库的特性保障这两个用户不会在同一时间段预定同一个会议室。

摘自《网易2018校园招聘数据分析工程师笔试卷》第8题

❤️ 「更多数据分析真题」
《数据分析真题日刷 | 目录索引》


1. 建表

1.1 用户表

-- 用户表(用户id,用户名,部门,职位)

CREATE TABLE `test`.`users` (
  `user_id` INT NOT NULL,
  `user_name` VARCHAR(45) NOT NULL,
  `department` VARCHAR(45) NOT NULL,
  `position` VARCHAR(45) NOT NULL,
  PRIMARY KEY (`user_id`));

网易2018校园招聘数据分析工程师笔试卷 —— SQL整理_第1张图片

1.2 会议室表

-- 会议室表(会议室id,办公楼编号,楼层,会议室门牌,会议室类型id)

CREATE TABLE `test`.`rooms` (
  `room_id` INT NOT NULL,
  `building_num` INT NOT NULL,
  `floor` INT NOT NULL,
  `room_num` INT NOT NULL,
  `type_id` INT NOT NULL,
  PRIMARY KEY (`room_id`));

网易2018校园招聘数据分析工程师笔试卷 —— SQL整理_第2张图片
1.3 会议室类型表

-- 会议室类型(类型id,容纳人数,是否有投影仪,是否有电话,是否有视频电话)

CREATE TABLE `test`.`room_type` (
  `type_id` INT NOT NULL,
  `acc_num` INT NOT NULL,
  `projector` TINYINT NOT NULL,
  `tel` TINYINT NOT NULL,
  `videocall` TINYINT NOT NULL,
  PRIMARY KEY (`type_id`));

网易2018校园招聘数据分析工程师笔试卷 —— SQL整理_第3张图片
1.4 会议订阅表

-- 会议订阅表(用户id,会议室id,订阅开始时间,订阅结束时间)

CREATE TABLE `test`.`booking` (
  `user_id` INT NOT NULL,
  `room_id` VARCHAR(45) NOT NULL,
  `start_time` VARCHAR(45) NOT NULL,
  `end_time` VARCHAR(45) NOT NULL,
  PRIMARY KEY (`user_id`, `room_id`));

网易2018校园招聘数据分析工程师笔试卷 —— SQL整理_第4张图片


2. 查出2017-09-11 10:00:00 至 2017-09-11 12:00:00没有被人预定过的会议室id列表,要求容纳人数在10人以上,有投影仪和视频电话。

-- 查询

SELECT r1.room_id -- , r3.start_time, r3.end_time
FROM rooms AS r1 LEFT JOIN room_type AS r2 ON r1.type_id = r2.type_id
LEFT JOIN booking AS r3 ON r1.room_id = r3.room_id
WHERE  r2.acc_num > 10 AND r2.projector = 1 AND r2.videocall = 1 AND 
	((r3.start_time NOT BETWEEN '2017-09-11 10:00:00' AND '2017-09-11 12:00:00'
	AND r3.end_time NOT BETWEEN '2017-09-11 10:00:00' AND '2017-09-11 12:00:00') OR r3.start_time IS NULL );


3.添加索引加速查询。

-- 添加索引
ALTER TABLE room_type ADD INDEX roomtype_index (acc_num, projector, videocall);
ALTER TABLE booking ADD INDEX booking_index (start_time, end_time);

-- 查询
SELECT r1.room_id -- , r3.start_time, r3.end_time
FROM rooms AS r1 LEFT JOIN room_type AS r2 ON r1.type_id = r2.type_id
LEFT JOIN booking AS r3 ON r1.room_id = r3.room_id
WHERE  r2.acc_num > 10 AND r2.projector = 1 AND r2.videocall = 1 AND 
	((r3.start_time NOT BETWEEN '2017-09-11 10:00:00' AND '2017-09-11 12:00:00'
	AND r3.end_time NOT BETWEEN '2017-09-11 10:00:00' AND '2017-09-11 12:00:00') OR r3.start_time IS NULL );

使用 EXPLAIN 命令,显示mysql如何使用索引来处理select语句以及连接表。
在这里插入图片描述
key: 实际使用的索引。如果为NULL,则没有使用索引。

可见,已成功添加并使用索引。


4. 请问如果两个用户同时预定,如何利用数据库的特性保障这两个用户不会在同一时间段预定同一个会议室。

一些思路和points:

  1. 事务

一个事务的例子:
tim要给bill转账100块钱:

  1. 检查tim的账户余额是否大于100块;
  2. tim的账户减少100块;
  3. bill的账户增加100块;

这三个操作就是一个「事务」,必须打包执行,要么全部成功,要么全部不执行,其中任何一个操作的失败都会导致所有三个操作“不执行”——回滚。
————————————————
版权声明:本文为CSDN博主「Amazing_deron」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Deronn/article/details/86135646

使用事务更新数据库,即订阅一个会议室的两个步骤形成一个事务,打包执行,要么全部成功,要么全部不执行,回到原数据状态。

事务具有原子性,一致性,隔离性,持久性

  • 原子性:事务必须是一个自动工作的单元,要么全部执行,要么全部不执行。
  • 一致性:事务结束的时候,所有的内部数据都是正确的。
  • 隔离性:并发多个事务时,各个事务不干涉内部数据,处理的都是另外一个事务处理之前或之后的数据。
  • 持久性:事务提交之后,数据是永久性的,不可再回滚。
  1. 数据库锁

在多用户都用事务同时访问同一个数据资源的情况下,有可能造成以下几种数据错误:

  • 不可重复读:
    如果一个用户在一个事务中多次读取一条数据,而另外一个用户则同时更新啦这条数据,造成第一个用户多次读取数据不一致。
  • 脏读:
    第一个事务读取第二个事务正在更新的数据表,如果第二个事务还没有更新完成,那么第一个事务读取的数据将是一半为更新过的,一半还没更新过的数据,这样的数据毫无意义。
  • 幻读:
    第一个事务读取一个结果集后,第二个事务,对这个结果集经行增删操作,然而第一个事务中再次对这个结果集进行查询时,数据发现丢失或新增。
然而数据库锁,就是为解决这些问题所生的,他的存在使得一个事务对他自己的数据块进行操作的时候,而另外一个事务则不能插足这些数据块。这就是所谓的数据库

————————————————
版权声明:本文为CSDN博主「Amazing_deron」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Deronn/article/details/86135646


5. 讨论

  • 查询语句中表链接为什么用LEFT JOIN?

    应该以会议室表rooms为主表。例如,存在以下情况:会议室表包含所有会议室1-5,会议订阅表booking中仅有会议室1-4被预订了。会议室5一直是空的,无人预定。如果用INNER JOIN 则会议室5无法被查询到。

  • 为什么查询语句中,IS NULL的记录也被选中?
    当存在上述情况时,IS NULL 即对应那些尚未被预定过的空会议室。

  • 建立会议室预定表booking时,该如何设置主键?
    目前,我是以(user_id, room_id)一起作为主键。可是,同一个人不可以在不同时间段重复定同一个房间吗?例如,

    user_id room_id start_time end_time
    1 3 2019-07-11 10:00:00 2019-07-11 12:00:00
    1 3 2019-07-11 15:00:00 2019-07-11 19:00:00

这种情况下,如何设置主键呢?

你可能感兴趣的:(#,SQL学习笔记,#,数据分析真题,数据分析岗秋招,面经,总结,学习资料汇总,数据库,SQL,编程,网易,数据分析)