关系型数据库(SQL)相关练习题目

巧了我就是萌 提交于 2020-01-13 19:18:11

一、简答题。

1. MySQL常见的三种存储引擎(InnoDB、MyISAM、MEMORY)的区别(至少5点)?

答:首先呢,我们要知道,引擎(Engine)是电子平台上开发程序或系统的核心组件。利用引擎,开发者可迅速建立、铺设程序所需的功能,或利用其辅助程序的运转。一般而言,引擎是一个程序或一套系统的支持部分。常见的程序引擎有游戏引擎,搜索引擎,杀毒引擎等。简单来说,存储引擎就是指表的类型以及表在计算机上的存储方式

存储引擎的概念是MySQL的特点,Oracle中没有专门的存储引擎的概念,Oracle有OLTP和OLAP模式的区分。不同的存储引擎决定了MySQL数据库中的表可以用不同的方式来存储。我们可以根据数据的特点来选择不同的存储引擎。

在MySQL中的存储引擎有很多种,我们可以可以通过“SHOW ENGINES”语句来查看。关于InnoDB、MyISAM、MEMORY这三种存储引擎的区别如下:

1).InnoDB存储引擎

  1. InnoDB给MySQL的表提供了事务处理回滚崩溃修复能力多版本并发控制的事务安全。在MySQL从3.23.34a开始包含InnnoDB。它是MySQL上第一个提供外键约束的表引擎。而且InnoDB对事务处理的能力,也是其他存储引擎不能比拟的。靠后版本的MySQL的默认存储引擎就是InnoDB。
  2. InnoDB存储引擎总支持AUTO_INCREMENT。自动增长列的值不能为空,并且值必须唯一。MySQL中规定自增列必须为主键。在插入值的时候,如果自动增长列不输入值,则插入的值为自动增长后的值;如果输入的值为0或空(NULL),则插入的值也是自动增长后的值;如果插入某个确定的值,且该值在前面没有出现过,就可以直接插入。
  3. InnoDB还支持外键(FOREIGN KEY)。外键所在的表叫做子表,外键所依赖(REFERENCES)的表叫做父表。父表中被字表外键关联的字段必须为主键。当删除、更新父表中的某条信息时,子表也必须有相应的改变,这是数据库的参照完整性规则
  4. InnoDB中,创建的表的表结构存储在.frm文件中(我觉得是frame的缩写吧)。数据和索引存储在innodb_data_home_dir和innodb_data_file_path定义的表空间中。

总结:InnoDB的优势在于提供了良好的事务处理、崩溃修复能力和并发控制。缺点是读写效率较差,占用的数据空间相对较大。

2).MyISAM存储引擎

  1. MyISAM是MySQL中常见的存储引擎,曾经是MySQL的默认存储引擎。MyISAM是基于ISAM引擎发展起来的,增加了许多有用的扩展。
  2. MyISAM的表存储成3个文件。文件的名字与表名相同。拓展名为frmMYDMYI。其实,frm文件存储表的结构;MYD文件存储数据,是MYData的缩写;MYI文件存储索引,是MYIndex的缩写。
  3. 基于MyISAM存储引擎的表支持3种不同的存储格式。包括静态型、动态型和压缩型。其中,静态型是MyISAM的默认存储格式,它的字段是固定长度的;动态型包含变长字段,记录的长度不是固定的;压缩型需要用到myisampack工具,占用的磁盘空间较小。

总结:MyISAM的优势在于占用空间小,处理速度快。缺点是不支持事务的完整性和并发性。

3).MEMORY存储引擎

 

  1. MEMORY是MySQL中一类特殊的存储引擎。它使用存储在内存中的内容来创建表,而且数据全部放在内存中。这些特性与前面的两个很不同。
  2. 每个基于MEMORY存储引擎的表实际对应一个磁盘文件。该文件的文件名与表名相同,类型为frm类型。该文件中只存储表的结构。而其数据文件,都是存储在内存中,这样有利于数据的快速处理,提高整个表的效率。值得注意的是,服务器需要有足够的内存来维持MEMORY存储引擎的表的使用。如果不需要了,可以释放内存,甚至删除不需要的表。

总结:MEMORY默认使用哈希索引。速度比使用B型树索引快。如果想用B型树索引,可以在创建索引时指定。

注意,MEMORY用到的很少,因为它是把数据存到内存中,如果内存出现异常就会影响数据。如果重启或者关机,所有数据都会消失。因此,基于MEMORY的表的生命周期很短,一般是一次性的。

下面顺便说一下我们在使用当中如何选择合适的引擎:

我们要知道每种存储引擎都有自己的优缺点,不能笼统地说谁比谁好。下表大致说明了集中引擎的特点:

                                                                            表1:存储引擎的对比                          

              

InnoDB支持事务处理,支持外键,支持崩溃修复能力和并发控制。如果需要对事务的完整性要求比较高(比如银行),要求实现并发控制(比如售票),那选择InnoDB有很大的优势。如果需要频繁的更新、删除操作的数据库,也可以选择InnoDB,因为支持事务的提交(commit)和回滚(rollback)。 

MyISAM插入数据快,空间和内存使用比较低。如果表主要是用于插入新记录和读出记录,那么选择MyISAM能实现处理高效率。如果应用的完整性、并发性要求比 较低,也可以使用。

MEMORY所有的数据都在内存中,数据的处理速度快,但是安全性不高。如果需要很快的读写速度,对数据的安全性要求较低,可以选择MEMOEY。它对表的大小有要求,不能建立太大的表。所以,这类数据库只使用在相对较小的数据库表。

注意,同一个数据库也可以使用多种存储引擎的表。如果一个表要求比较高的事务处理,可以选择InnoDB。这个数据库中可以将查询要求比较高的表选择MyISAM存储。如果该数据库需要一个用于查询的临时表,可以选择MEMORY存储引擎。

2. 数据库事务的四个特性及含义

答:ACID 表示事务的特性:原子性、一致性、隔离性和持久性。

  1. 原子性(Atomic):事务中各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败;
  2. 一致性(Consistent):事务结束后系统状态是一致的;
  3. 隔离性(Isolated):并发执行的事务彼此无法看到对方的中间状态;
  4. 持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难性的失败。通过日志和同步备份可以在故障发生后重建数据。

3. 数据库三范式是什么?

答:经过研究和对使用中问题的总结,对设计数据库提出了一些规范,这些规范被称为范式

  • 第一范式(1NF): 数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性存在传递函数依赖关系。即列不可拆分,即无重复的域。
  • 第二范式(2NF): 完全依赖于主键,消除非主属性对主码的部分函数依赖。即唯一标识,即拥有实体的唯一标识( 身份证、学号等)。
  • 第三范式(3NF): 每个非关键字列都独立于其他非关键字列,并依赖于关键字,第三范式指数据库中不能。即引用主键,即每列数据都与主键直接相关。

注意:关系型数据库有六种范式。一般情况下,我们不会精确到最高级别范式,只需满足第三范式(3NF)就行了。

4. 数据库支持的SQL数据类型常用的有哪些?

答:数据库支持的SQL数据类型常用的有:

1)字符型数据:char\varchar\text,这几种数据类型都是用来装字符串的
char 固定长度存储数据
varcahr 按变长存储数据
text 当你需要存储非常大量的字符串时使用
2)日期时间型数据:datetime、smalldatetime,都是用于存储日期和时间信息
datetime:存放1/1/1753-12/31/9999的时间数据,精确到0.001s
smalldatetime: 存放1/1/1900-6/6/2079的时间,精确到秒
3)整数型数据:bigint、int、smallint、tinyint,用于存放整数
bigint 从 -2^63 (-9223372036854775808) 到 2^63-1 (9223372036854775807) 的整型数据(所有数字)。
int 从 -2^31 (-2,147,483,648) 到 2^31 - 1 (2,147,483,647) 的整型数据(所有数字)。
smallint 从 -2^15 (-32,768) 到 2^15 - 1 (32,767) 的整数数据。
tinyint 从 0 到 255 的整数数据。
4)精确小数型数据:decimal、numeric,用于存放小数
5)近似数值类型:float、real,用于存放近似数
6)位类型数据bit
5. SQL数据类型varchar和char的区别?

答:区别如下:

  • varchar:可变长的字符串,需要在声明字段时指定能存储的最大字符数,真实占用的空间取决于存入的字符数,存入的越多占用空间越多。适合保存内容长度不定的字符类型数据。存储数据的大小,mysql5.0以前0~255字节,mysql5.0以后0~65535字节。
  • char:定长字符串,需要在声明字段时指定固定字符数。即使存入的字符数少于该长度,该字段也会占用该固定长度。适合存储长度不变的字符类型数据。存储数据的大小,0~255字节。

6. SQL 约束有哪几种并解释含义(eg:NOT NULL、UNIQUE等)?

答:如下:

  • not null(非空)
  • unique(唯一)
  • primary key(非空,唯一,只能有一个主键)
  • foreign(外键)
  • check(强制数据满足要求)

7. 数据库内连表、左连表、右连表有什么区别?

答:区别如下:

  • 内连表:table_A inner join table_B,表 table_A 和 table_B 相匹配的行出现在结果集中。
  • 左连表:table_A left join table_B,表 table_A 和 table_B 相匹配的行出现在结果集中,外加表 table_A 中独有的数据,为对应的数据用 null 填充。
  • 右连表:table_A right join table_B,表 table_A 和 table_B 相匹配的行出现在结果集中,外加表 table_B 中独有的数据,为对应的数据用 null 填充。

8. SQL语句查询时如何实现分页?

#表示从第m条数据开始,获取 count 条数据,默认情况下索引从0开始
select * from 表名 limit m,count

9. 什么是SQL注入?

1)SQL注入(SQLi)是一种注入攻击,可以执行恶意SQL语句。它通过将任意SQL代码插入数据库查询,使攻击者能够完全控制Web应用程序后面的数据库服务器。攻击者可以使用SQL注入漏洞绕过应用程序安全措施;可以绕过网页或Web应用程序的身份验证和授权,并检索整个SQL数据库的内容;还可以使用SQL注入来添加,修改和删除数据库中的记录。

SQL注入漏洞可能会影响使用SQL数据库(如MySQL,Oracle,SQL Server或其他)的任何网站或Web应用程序。犯罪分子可能会利用它来未经授权访问用户的敏感数据:客户信息,个人数据,商业机密,知识产权等。SQL注入攻击是最古老,最流行,最危险的Web应用程序漏洞之一。

2)SQL注入攻击的类型:

带内注入:这是典型的攻击,攻击者可以通过相同的通信通道发起攻击并获得结果。这是通过两种带内技术完成的:

● 基于错误的SQL注入:从显示的错误消息中获取有关数据库的信息

● 基于联合的SQL注入:依赖于攻击者能够将UNION ALL被盗信息的结果与合法结果连接起来。

这两种技术都依赖于攻击者修改应用程序发送的SQL,以及浏览器中显示的错误和返回的信息。如果应用程序开发人员或数据库开发人员无法正确地参数化他们在查询中使用的值,那么它会成功。两者都是试错法,可以检测到错误。

盲注入:也称为推理SQL注入,盲注入攻击不会直接从目标数据库中显示数据;相反,攻击者会仔细检查行为中的间接线索。HTTP响应中的详细信息,某些用户输入的空白网页以及数据库响应某些用户输入需要多长时间,这些都可以是线索,具体取决于攻击者的目标。他们还可以指向攻击者尝试的另一个SQLi攻击途径。

带外注入:这种攻击有点复杂,当攻击者无法在单个直接查询 - 响应攻击中实现其目标时,攻击者可能会使用此攻击。通常,攻击者会制作SQL语句,这些语句在呈现给数据库时会触发数据库系统创建与攻击者控制的外部服务器的连接。以这种方式,攻击者可以收集数据或可能控制数据库的行为。

二阶注入就是一种带外注入攻击。在这种情况下,攻击者将提供SQL注入,该注入将由数据库系统的单独行为存储和执行。当二级系统行为发生时(它可能类似于基于时间的作业或由其他典型管理员或用户使用数据库触发的某些事情)并且执行攻击者的SQL注入,那就是当“伸出”到系统时攻击者控制发生了。

3)SQL注入的产生条件:

  • 有参数传递
  • 参数值带入数据库查询并且执行

4)如何防止SQL注入攻击?

  • 使用预编译语句,绑定变量。
  • 使用安全的存储过程对抗SQL注入。
  • 检查数据类型。
  • 使用安全函数。

10. 数据库怎么优化查询效率(参考解释)?

  1. 储存引擎选择:如果数据表需要事务处理,应该考虑使用 InnoDB,因为它完全符合 ACID 特性。如果不需要事务处理,使用默认存储引擎 MyISAM 是比较明智的。
  2. 对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
  3. 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描。
  4. 应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描。
  5. 应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描。
  6. Update 语句,如果只更改 1、2 个字段,不要 Update 全部字段,否则频繁调用会引起明显的性能消耗,同时带来大量日志。
  7. 对于多张大数据量(这里几百条就算大了)的表 JOIN,要先分页再 JOIN,否则逻辑读会很高,性能很差。

二、SQL语句查询操作。

数据源: student.sql文件(上课时备份的数据库表信息)

# 1. 数据恢复,开启MariaDB后,首先创建一个数据库 StuProject
MariaDB [(none)]> create database  StuProject charset=utf8;
Query OK, 1 row affected (0.001 sec)
# 2. 退出数据库,在终端输入:
python@ubuntu:~ $ mysql -uroot -pmysql StuProject < student.sql
# 3. 查看数据恢复情况
MariaDB [(none)]> use StuProject;
MariaDB [StuProject]> show tables;
+----------------------+
| Tables_in_StuProject |
+----------------------+
| courses              |
| scores               |
| students             |
| teachers             |
+----------------------+
4 rows in set (0.000 sec)
# 5.成功~~
MariaDB [StuProject]> select * from courses;
+-------+-----------------+-----+
| cno   | cname           | tno |
+-------+-----------------+-----+
| 3-105 | 计算机导论      | 825 |
| 3-245 | 操作系统        | 804 |
| 6-166 | 数据电路        | 856 |
| 9-888 | 高等数学        | 100 |
+-------+-----------------+-----+
4 rows in set (0.001 sec)

1. 创建数据库表employees, 包含的信息有:

属性名 属性含义 属性类型
emp_no 员工编号 整形、主键、自增
birth_date 出生年月 日期、非空
name 姓名 字符串、非空
gender 性别 整形、非空、1-男 2-女
hire_date 入职日期 日期、非空
MariaDB [StuProject]> create table employees(
    -> emp_no int auto_increment primary key comment '员工编号',
    -> birth_date date not null comment '出生日期',
    -> name varchar(20) not null comment '姓名',
    -> gender int not null default 1 comment '男1女2',
    -> hire_date datetime not null comment '入职日期');

MariaDB [StuProject]> desc employees;
+------------+-------------+------+-----+---------+----------------+
| Field      | Type        | Null | Key | Default | Extra          |
+------------+-------------+------+-----+---------+----------------+
| emp_no     | int(11)     | NO   | PRI | NULL    | auto_increment |
| birth_date | date        | NO   |     | NULL    |                |
| name       | varchar(20) | NO   |     | NULL    |                |
| gender     | int(11)     | NO   |     | 1       |                |
| hire_date  | datetime    | NO   |     | NULL    |                |
+------------+-------------+------+-----+---------+----------------+
5 rows in set (0.002 sec)

2. 批量插入数据如下:

emp_no birth_date name gender hire_date
1 1996-10-10 高崎 2019-10-10
2 1995-10-10 刘欢 2019-6-10
3 1993-10-10 王佗 2019-1-10
4 1995-10-10 洪笙宁 2018-10-10
5 1991-2-1 张三 2017-10-10
MariaDB [StuProject]> insert into employees values
    -> (1,'1996-10-10','高崎','2','2019-10-10'),
    -> (2,'1995-10-10','刘欢',2,'2019-6-10'),
    -> (3,'1993-10-10','王佗',1,'2019-1-10'),
    -> (4,'1995-10-10','洪笙宁',1,'2018-10-10'),
    -> (5,'1991-2-1','张三',1,'2017-10-10');
    
MariaDB [StuProject]> select * from employees;
+--------+------------+-----------+--------+------------+
| emp_no | birth_date | name      | gender | hire_date  |
+--------+------------+-----------+--------+------------+
|      1 | 1996-12-12 | 高崎      |      2 | 2019-10-10 |
|      2 | 1995-10-10 | 刘欢      |      2 | 2019-06-10 |
|      3 | 1993-10-10 | 王佗      |      1 | 2019-01-10 |
|      4 | 1995-10-10 | 洪笙宁    |      1 | 2018-10-10 |
|      5 | 1991-02-01 | 张三      |      1 | 2017-10-10 |
+--------+------------+-----------+--------+------------+
5 rows in set (0.000 sec)

3. 更新高崎的出生日期为1996-12-12.

MariaDB [StuProject]> update employees set birth_date='1996-12-12' where name='高崎'; 
Query OK, 1 row affected (0.007 sec)
Rows matched: 1  Changed: 1  Warnings: 0

MariaDB [StuProject]> select * from employees where name='高崎';
+--------+------------+--------+--------+------------+
| emp_no | birth_date | name   | gender | hire_date  |
+--------+------------+--------+--------+------------+
|      1 | 1996-12-12 | 高崎   |      2 | 2019-10-10 |
+--------+------------+--------+--------+------------+
1 row in set (0.001 sec)


4. 统计员工总人数。

MariaDB [StuProject]> select count(*) as stu_conut  from employees;
+-----------+
| stu_conut |
+-----------+
|         5 |
+-----------+
1 row in set (0.001 sec)


5. 统计入职时间超过2年的员工姓名.(拓展知识, 查阅资料)

# 利用函数curdate()获取当前日期并利用 @dt将其保存起来
MariaDB [StuProject]> set @dt=curdate();
Query OK, 0 rows affected (0.000 sec)

MariaDB [StuProject]> select @dt;
+------------+
| @dt        |
+------------+
| 2020-01-10 |
+------------+
1 row in set (0.000 sec)

# 两年即730天
MariaDB [StuProject]> select * from employees where datediff(@dt, hire_date)>730;
+--------+------------+--------+--------+------------+
| emp_no | birth_date | name   | gender | hire_date  |
+--------+------------+--------+--------+------------+
|      5 | 1991-02-01 | 张三   |      1 | 2017-10-10 |
+--------+------------+--------+--------+------------+

6. 查找最晚入职员工的所有信息

MariaDB [StuProject]> select * from employees where hire_date=(select max(hire_date) from employees);
+--------+------------+--------+--------+------------+
| emp_no | birth_date | name   | gender | hire_date  |
+--------+------------+--------+--------+------------+
|      1 | 1996-12-12 | 高崎   |      2 | 2019-10-10 |
+--------+------------+--------+--------+------------+
1 row in set (0.002 sec)

7. 查询最早入职员工的所有信息

MariaDB [StuProject]> select * from employees where hire_date=(select min(hire_date) from employees);
+--------+------------+--------+--------+------------+
| emp_no | birth_date | name   | gender | hire_date  |
+--------+------------+--------+--------+------------+
|      5 | 1991-02-01 | 张三   |      1 | 2017-10-10 |
+--------+------------+--------+--------+------------+
1 row in set (0.001 sec)

8. 查询成绩在85到90分之间的学生姓名、课程名和成绩。
| 陆君   | 95031 |   86.0 |
| 匡明   | 95031 |   88.0 |
 

MariaDB [StuProject]> select sname as '姓名',cname as '课程', degree as '成绩' from scores
    -> right join students on students.sno=scores.sno
    -> right join courses on scores.cno=courses.cno
    -> group by degree having degree between 85 and 90;
+--------+-----------------+--------+
| 姓名   | 课程            | 成绩   |
+--------+-----------------+--------+
| 李军   | 数据电路        |   85.0 |
| 陆君   | 操作系统        |   86.0 |
| 匡明   | 计算机导论      |   88.0 |
+--------+-----------------+--------+
3 rows in set (0.003 sec)

9. 查询高等数学成绩最高的学生名和学生分数。
| 陆君   |   86.0 |
 

# 1. 查看得知最高分的学生为 | 103  | 3-105 |   92.0 | 103 | 陆君   | 男   | 1974-06-03 00:00:00 | 95031 |
MariaDB [StuProject]> select * from scores right join students on students.sno=scores.sno;
+------+-------+--------+-----+--------+------+---------------------+-------+
| sno  | cno   | degree | sno | sname  | ssex | sbirthday           | class |
+------+-------+--------+-----+--------+------+---------------------+-------+
| 103  | 3-245 |   86.0 | 103 | 陆君   | 男   | 1974-06-03 00:00:00 | 95031 |
| 105  | 3-245 |   75.0 | 105 | 匡明   | 男   | 1975-10-02 00:00:00 | 95031 |
| 109  | 3-245 |   68.0 | 109 | 王芳   | 女   | 1975-02-10 00:00:00 | 95031 |
| 103  | 3-105 |   92.0 | 103 | 陆君   | 男   | 1974-06-03 00:00:00 | 95031 |
| 105  | 3-105 |   88.0 | 105 | 匡明   | 男   | 1975-10-02 00:00:00 | 95031 |
| 109  | 3-105 |   76.0 | 109 | 王芳   | 女   | 1975-02-10 00:00:00 | 95031 |
| 101  | 3-105 |   64.0 | 101 | 李军   | 男   | 1976-02-20 00:00:00 | 95033 |
| 107  | 3-105 |   91.0 | 107 | 王丽   | 女   | 1976-01-23 00:00:00 | 95033 |
| 108  | 3-105 |   78.0 | 108 | 曾华   | 男   | 1977-09-01 00:00:00 | 95033 |
| 101  | 6-166 |   85.0 | 101 | 李军   | 男   | 1976-02-20 00:00:00 | 95033 |
| 107  | 6-106 |   79.0 | 107 | 王丽   | 女   | 1976-01-23 00:00:00 | 95033 |
| 108  | 6-166 |   81.0 | 108 | 曾华   | 男   | 1977-09-01 00:00:00 | 95033 |
+------+-------+--------+-----+--------+------+---------------------+-------+
12 rows in set (0.003 sec)

# 2. 获取
MariaDB [StuProject]> select sname as '姓名',cname as '课程', degree as '成绩' from scores
    -> right join students on students.sno=scores.sno
    -> right join courses on scores.cno=courses.cno
    -> where degree=(select max(degree) from scores);
+--------+-----------------+--------+
| 姓名   | 课程            | 成绩   |
+--------+-----------------+--------+
| 陆君   | 计算机导论      |   92.0 |
+--------+-----------------+--------+
1 row in set (0.001 sec)


10. 查询李军选修的课程名称。
| 计算机导论      |
| 数据电路        |

MariaDB [StuProject]> select sname as '姓名',cname as '课程' from scores 
    -> right join students on students.sno=scores.sno
    -> right join courses on scores.cno=courses.cno
    -> where sname='李军';
+--------+-----------------+
| 姓名   | 课程            |
+--------+-----------------+
| 李军   | 计算机导论      |
| 李军   | 数据电路        |
+--------+-----------------+
2 rows in set (0.001 sec)

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!